diff --git a/README.md b/README.md index b66f3c9b9d52bf9a769a894e2ef24ceeb247dc4b..0505dbb605d87d93ee9c0c59f0a30b7e0bd8139c 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,8 @@ The project follows the following structure below the `theories` folder: * `behavior.v` defines the notion of contextual refinement and expression well-formedness. * `adequacy.v` contains the resulting adequacy proof. * `examples` contains example optimizations, see below. +- `tree_borrows` contains the Simuliris development of Tree Borrows. + This development has its own README in `tree_borrows/README.md`. ## Theorems, definitions, and examples referenced in the paper diff --git a/_CoqProject b/_CoqProject index beae3548e47c677d13b0c28b1ff4e4153a3e3137..a982889c6e1eee3732cab25613e33b5ed5b9571a 100644 --- a/_CoqProject +++ b/_CoqProject @@ -124,7 +124,6 @@ theories/stacked_borrows/examples/coinductive.v ## Tree Borrows -theories/tree_borrows/helpers.v theories/tree_borrows/locations.v theories/tree_borrows/lang_base.v theories/tree_borrows/notation.v @@ -136,23 +135,16 @@ theories/tree_borrows/bor_semantics.v theories/tree_borrows/bor_lemmas.v theories/tree_borrows/lang.v -# Proofs directly against the operational semantics. -# Ultimately goes in a different direction but there are useful -# intermediate lemmas. -# Both of these files can be removed (after extracting some lemmas) -# if keeping them building slows down development too much. -theories/tree_borrows/steps_preserve.v -theories/tree_borrows/disjoint.v - # Actual Simuliris proof content for TB theories/tree_borrows/defs.v theories/tree_borrows/steps_foreach.v -theories/tree_borrows/steps_access.v +theories/tree_borrows/steps_preserve.v theories/tree_borrows/steps_wf.v theories/tree_borrows/steps_progress.v theories/tree_borrows/steps_inv.v theories/tree_borrows/tactics.v +theories/tree_borrows/wishlist.v theories/tree_borrows/class_instances.v theories/tree_borrows/tkmap_view.v theories/tree_borrows/logical_state.v @@ -171,7 +163,6 @@ theories/tree_borrows/steps_all.v theories/tree_borrows/primitive_laws.v theories/tree_borrows/proofmode.v theories/tree_borrows/early_proofmode.v -theories/tree_borrows/wishlist.v theories/tree_borrows/tree_access_laws.v theories/tree_borrows/tag_protected_laws.v theories/tree_borrows/loc_controlled_laws.v @@ -202,10 +193,20 @@ theories/tree_borrows/examples/protected/mutable_reorder_read_down.v theories/tree_borrows/examples/protected/mutable_reorder_read_up.v theories/tree_borrows/examples/protected/shared_reorder_read_down_escaped.v theories/tree_borrows/examples/protected/shared_reorder_read_up_escaped.v +theories/tree_borrows/examples/protected/shared_insert_read.v theories/tree_borrows/examples/protected/mutable_reorder_write_down_activated.v theories/tree_borrows/examples/protected/mutable_reorder_write_up_activated.v +theories/tree_borrows/examples/protected/mutable_reorder_write_up_activated_paper.v theories/tree_borrows/examples/unprotected/mutable_delete_read.v theories/tree_borrows/examples/unprotected/shared_delete_read_escaped.v theories/tree_borrows/examples/unprotected/shared_delete_read_escaped_coinductive.v theories/tree_borrows/examples/lib.v theories/tree_borrows/examples/pure.v + +# Proofs directly against the operational semantics. +# This results in a proof that reads can be reordered. +theories/tree_borrows/read_read_reorder/low_level.v +theories/tree_borrows/read_read_reorder/read_reorder.v +theories/tree_borrows/read_read_reorder/equivalence_def.v + + diff --git a/theories/tree_borrows/README.md b/theories/tree_borrows/README.md index 83aeafaad388821e3e020d9c702c92afd282621d..83d9d1ddde5bb1a7ec5eeb55bd671f5724e1b862 100644 --- a/theories/tree_borrows/README.md +++ b/theories/tree_borrows/README.md @@ -2,14 +2,154 @@ Forked and adapted from the sibling folder `../stacked_borrows` with the same structure. -* `tree.v`, `locations.v` contain preliminary definitions. -* `lang_base.v`, `expr_semantics.v`, `bor_semantics.v`, and `lang.v` contain the language definition. -* `tree_lemmas.v`, `bor_lemmas.v` and `steps_wf.v` contain basic lemmas to help with the manipulation of trees. -* [WIP] `logical_state.v` defines the invariants and instantiates the simulation relation. -* [WIP] `steps_refl.v` and `steps_opt.v` prove the main execution lemmas. -* [WIP] `behavior.v` defines the notion of contextual refinement and expression well-formedness. -* [WIP] `adequacy.v` contains the resulting adequacy proof. -* [WIP] `examples` contains example optimizations. - -In addition, `disjoint.v` provides proofs of simple reorderings (swapping adjacent operations in -a sequential setting) directly against the operational semantics. +## Structure + +### TCB + +Our trusted computing base is the definition of our borrow calculus language. +It consists of the following files: + +* `tree.v` defines our notion of trees, where nodes are indexed by tags. +* `locations.v` defines pointers in our block-based (CompCert) memory model. +* `lang_base.v` defines the syntax of our core calculus, which is mostly unchanged from the one in `../stacked_borrows` +* `expr_semantics.v` defines the semantics of expressions, ignoring the aliasing model. It is also mostly unchanged from SB. +* `bor_semantics.v` defines the semantics of retags and the aliasing. It is where most of Tree Borrows' core definitions live. +* `parallel_subst.v` defines parallel substitution. +* `lang.v` finally instantiates the language interface of Simuliris. + +Most of our example files construct an end-to-end proof against the semantics outlined in here, using the machinery provided by Simuliris. +Of course, that end-to-end proof uses Simuliris' definition of refinement, but this definition is already in the literature. + + +### Development + +* `defs.v` contains some more logical definitions, notably that of well-formed states (`state_wf`). +* `tactics.v` and `class_instances.v` are some more Simuliris-related infrastructure. +* `tree_lemmas.v`, `bor_lemmas.v`, `steps_foreach.v`, `steps_inv.v`, and `steps_preserve.v` contain basic lemmas to help with the manipulation of trees. +* `steps_wf.v` proves that all OpSem steps preserve state well-foundedness. +* `tree_access_laws.v` contains more complex lemmas about the entire memory (`trees`) rather than single allocations (`tree`). +* `steps_progress.v` states success conditions for the various borrow steps so that we can prove absence of UB or exploit presence of UB. +* `tkmap_view.v` defines views (partial ownership) of the global maps we use to remember the kind of each tag. +* `trees_equal/` contains a number of files related to a `trees_equal` binary relation between trees. + In Stacked Borrows the source stack and the target stack are always identical. + In Tree Borrows that is no longer the case, and this relation describes the extent to which they are allowed to differ. +* `logical_state.v` defines the invariants and instantiates the simulation relation, + using among others a notion of when trees are similar in `trees_equal/`. +* `tag_protected_laws.v` contains reasoning principles about protectors. +* `loc_controlled_laws.v` contains reasoning principles for "heaplets" and tags. +* `steps_refl.v` and `steps_opt.v` prove the main execution lemmas. +* `steps_all.v`, `proofmode.v`, and `primitive_laws.v` collect all laws of the program logic. +* `wf.v` defines well-formedness for expressions, in particular that they contain no raw location literals. +* `behavior.v` defines the notion of contextual refinement and expression well-formedness. +* `adequacy.v` contains the resulting adequacy proof. +* `examples/` contains example optimizations, further subdivided into + - `unprotected/` optimizations, which are program transformations that can be applied even in the absence of protectors, + - `protected/` optimizations, which require a protector to hold, + - `impossible/` optimizations used to hold under Stacked Borrows, + but we know of counter-examples under Tree Borrows. + +In addition, `read_read_reorder/` provides proofs of simple reorderings +(swapping adjacent operations in a sequential setting) +directly against the operational semantics. +You can find more details in the associated `README.md`. + +## Correspondence with Section 5 + +Section 5 has three examples, one for deleting reads, one for deleting writes, and one for reordering reads. + +### Paragraph 1: Deleting Reads (Example 16) + +This example corresponds to the one in `examples/unprotected/shared_delete_read_escaped.v`. +The Coq example is very close to the one in the paper. +The only difference is that `f` has an extra argument in Coq, which corresponds to the implicit environment that closures have in Rust. + +In the justification in the paper (around line 818), we say that a protected Reserved cousing of a tag can be conflicted in one side, +but not in the other. In Coq, this is achieved using the `pseudo_conflicted` case of `perm_eq_up_to_C` in line 88 of `trees_equal_base.v`. + +### Paragraph 2: Deleting Writes (Optimizing with Protectors) (Example 17) + +This example corresponds to the one in `examples/protected/mutable_reorder_write_up_activated_paper.v`. +This Coq example corresponds very closely to the one in the paper. +The only difference is that `f` and `g` have an extra argument in Coq, which corresponds to the implicit environment that closures have in Rust. + +This is also where we need (and the paper finally explains) protector end semantics. +Protector end semantics ensure that two states remain `trees_equal` even when a protector is removed. +The main lemma here is `trees_equal_remove_call` in line 1160 of `trees_equal_endcall_law.v`, +which shows that after the protector end access, `trees_equal` is preserved even without the just ended protector. + +### Paragraph 4: Reordering Reads (Example 18) + +This is proven in `read_read_reorder`, particularly in `read_reorder.v`. +These proofs do not use the `simuliris` library, but instead they do a much simpler equivalence proof directly against the operational semantics. +This is because these proofs only hold for a non-concurrent language. +We suspect that they also hold in a concurrent setting, but this would require data race reasoning, and thus we have not proven that. + +Specifically, the simple notion of "equivalence after a few steps" is in `equivalence_def.v`. +The proof that the two reads can be reordered is in `read_reorder.v`. +The file `low_level.v` contains low-level lemmas used in `read_reorder.v` + +### Other Examples From The Paper + +Example 1 is similar to the one shown in `examples/unprotected/mutable_delete_read.v`. +The one shown in Coq has two places where arbitrary unknown functions are called, and Example 1 is just a special case of that, if one instantiates these unknown functions correctly. + +We have not shown Example 14, but two examples similar to it: +* `examples/unprotected/shared_delete_read_escaped_coinductive.v` demonstrates reasoning in a while loop. + But note that this does not insert a read if there is none. Also, the tag is not protected. +* `examples/protected/shared_insert_read.v` demonstrates that reads can be inserted on protected tags. + +This shows that the program logic has all the reasoning primitives required for verifying Example 14, +so that its verification would be straightforward, just needing to combine the two reasoning principles. + +## Program Logic + +As mentioned in the paper, the way we proved these refinements is using a program logic. +This program logic can prove refinements, and uses several separation logic resources to accomplish this. +You can see the separation logic in action in the examples shown above. +Here, we explain the resources that you will encounter when stepping through the proof. + +The `$$` resource associates a "tag" with a "tag kind." Remember that each tag corresponds to a specific node in the borrow tree. +The tag kind is a very coarse over-approximation of the shape of the tree from that specific node. + +The simplemost kind is `tk_local`, which says that the tree here is a singleton, and this tag is the only tag in the tree. +`tk_local` tags are used for new fresh allocations that do not have their address taken, and allows treating them as local variables. + +To talk about the value of such a local tag, the "heaplet points-to" `l ↦t∗[tk_local]{t} vs` is used. +This resource comes in two kinds, with `l ↦t∗[tk_local]{t} vs` for the target side and `l ↦s∗[tk_local]{t} vs` for the source side. +In it, `vs` is a list of values, and this heaplet expresses knowledge that the values stored at `l` are `vs`. `vs` is a list so that we can talk about arrays; in many examples it is a singleton list. + +This "heaplet" resource works like the separation logic points-to. The version with `tk_local` is exclusive, expressing that this location is "local" to the function. +`tk_local` heaplets are very unrestricted: they can be set to arbitrary values in either source and target, just like local variables. +The rules for heaplets with a different tag kind are more restricted, as we see now. + +The next tag kind is `tk_unq`, which corresponds to a mutable reference. It is created when a reference is mutably retagged. +It has two kinds: `tk_unq tk_res` and `tk_unq tk_act`, which correspond to the reservation and activation phase of a mutable reference. +When a `tk_unq tk_res` is written to, it transitions to `tk_unq tk_act` (See rule `sim_write_activate_unprotected` in `step_laws/steps_unique.v`). + +The heaplet points-tos for `tk_unq` are still exclusive, since a mutable reference should give us unique access to the memory. +Unfortunately, this is only true with protectors (see below); without protectors, these tags must be written to in lockstep and already deleting reads is restricted. + +Finally, there is `tk_pub`, which is the "default" permission that is also not exclusive, but persistent. +Once a tag has been made public, the program logic exposes very weak guarantees on it, but it can be passed around freely. +This corresponds to how it's hard to optimize around unknown pointers. + +`tk_pub` tags come in two kinds: Those with, and those without a heaplet. +Those without a heaplet carry almost no information. +Those with a heaplet are more interesting: They correspond to "frozen" tags. +`tk_pub` heaplets are also persistent, so the values stored there can not change their value. +This allows passing a shared reference to another function and later still knowing that the function could not have changed the value. + +At this point, we should mention that all heaplets represent "conditional" knowledge: They basically say that the given value is stored in memory, or that alternatively the corresponding tag has since become `Disabled`. +This allows proving rules like lockstep reads (`sim_copy` in `step_laws/steps_unique.v`), based on the argument that either the source has UB when the tag is `Disabled`, or we know that the heaplet is still alive and hence the read is possible. +This means that lockstep rules are typically easy to prove with our setup, but proving anything about single-sided reads is much more difficult, which is why we can only prove read removal optimizations without protectors. + +### Protectors + +Protectors allow us to prove much more optimizations. +The reason here is that protectors give us "independent" and exclusive ownership that a certain tag is has not yet become `Disabled`. +This is expressed using permissions like `c @@ <[t_i:=<[i +â‚— 0%nat:=EnsuringAccess Strongly]> ∅]> ∅`, which say that call `c` protects tag `t_i` at offset `i`. +Once we have such a protector permission, we are able to treat `tk_unq` tags almost like `tk_local` tags: They can be read from and written to individually, can have unrelated values on each side, etc. (See `step_laws/steps_prot.v`.) + +The only restrictions here are that the activating write must still happen in lockstep (`sim_write_activate_protected` in `step_laws/steps_unique.v`), and that the values must be related when the protector ends (line 316, for lemma `sim_protected_unprotect` in `step_laws/steps_opt.v`). +This corresponds to what we claimed in the paper (860-870). + diff --git a/theories/tree_borrows/behavior.v b/theories/tree_borrows/behavior.v index 9a27df7deeb12cc4ecbcf7925697adedcddc56fb..d22e3758edaf81fe2e1c4028c4c27c1c2b119f21 100755 --- a/theories/tree_borrows/behavior.v +++ b/theories/tree_borrows/behavior.v @@ -20,6 +20,7 @@ Definition obs_scalar (sc_t sc_s : scalar) := | _, _ => False end . + Definition obs_value (v_t v_s : value) : Prop := Forall2 obs_scalar v_t v_s. Definition obs_result (r_t r_s : val bor_lang) : Prop := match r_t, r_s with diff --git a/theories/tree_borrows/bor_lemmas.v b/theories/tree_borrows/bor_lemmas.v index 259269314005933e20baed9bc6bd5256e0303357..773a1fad384da504054b711ca9bddc9c99cec6f1 100644 --- a/theories/tree_borrows/bor_lemmas.v +++ b/theories/tree_borrows/bor_lemmas.v @@ -2,6 +2,13 @@ From iris.prelude Require Import prelude options. From simuliris.tree_borrows Require Import lang_base notation bor_semantics tree tree_lemmas. From iris.prelude Require Import options. +(** A collection of lemmas to reason about the current state of the tree. + These are not invariants (you will find those in [steps_wf.v]. + Rather, consider that this file is to [bor_semantics.v] what + [tree_lemmas.v] is to [tree.v]: these are specialized lemmas + to reason about the instanciation of trees that is specifically + with [item]s containing [tag]s (and some non-tree lemmas also). *) + Lemma most_init_comm m1 m2 : most_init m1 m2 = most_init m2 m1. Proof. by destruct m1, m2. Qed. @@ -32,6 +39,9 @@ Lemma exists_somewhere a + b + c ≥ 1 <-> a ≥ 1 \/ b ≥ 1 \/ c ≥ 1. Proof. lia. Qed. +(** [tree_unique] is defined by [count_nodes]. + [tree_contains] is defined by [exists_node]. + Here are some lemmas that relate the two. *) Lemma unique_exists {tr tg} : tree_unique tg tr -> tree_contains tg tr. @@ -66,7 +76,6 @@ Proof. reflexivity. Qed. - Lemma count_0_not_exists tr tg : tree_count_tg tg tr = 0 <-> ~tree_contains tg tr. @@ -93,6 +102,8 @@ Proof. + apply IHtr2. auto. Qed. +(** [tree_item_determined] is defined by a [forall_nodes]. + We can similarly relate it to predicates derived from [count_nodes]. *) Lemma absent_determined tr tg : tree_count_tg tg tr = 0 -> forall it, tree_item_determined tg it tr. @@ -148,6 +159,12 @@ Proof. - right; right; auto. Qed. +(** Some of the most important lemmas here. + They characterizes insertion of a child node in terms of its relationship + with other nodes. If you insert [n'] as a child of [n]... + then in the resulting tree [n'] is a child of [n]! + Not a groundbreaking statement, but necessary due to our representation + of trees. *) Lemma insert_eqv_strict_rel t t' (ins:item) (tr:tree item) (search:item -> Prop) {search_dec:forall it, Decision (search it)} : ~IsTag t ins -> @@ -225,69 +242,6 @@ Proof. erewrite exists_sibling_insert. eauto. Qed. -Lemma join_map_eqv_strict_rel t t' (tr tr':tree item) : - forall fn, - (forall it it', fn it = Some it' -> itag it = itag it') -> - join_nodes (map_nodes fn tr) = Some tr' -> - StrictParentChildIn t t' tr <-> StrictParentChildIn t t' tr'. -Proof. - intros fn FnPreservesTag Success. - generalize dependent tr'. - unfold StrictParentChildIn. - induction tr as [|data ? IHtr1 ? IHtr2]; intros tr' Success; simpl in *. - - inversion Success; auto. - - destruct (destruct_joined _ _ _ _ Success) as [data' [tr1' [tr2' [EqTr' [EqData' [EqTr1' EqTr2']]]]]]. - rewrite IHtr1; [|eapply EqTr1']. - rewrite IHtr2; [|eapply EqTr2']. - subst; simpl. - split; intro H; destruct H as [H[??]]; try repeat split; try assumption. - all: intro Hyp. - + rewrite <- join_map_preserves_exists. - * apply H. erewrite FnPreservesTag; eassumption. - * intros; subst. erewrite FnPreservesTag; eauto. - * apply EqTr2'. - + rewrite join_map_preserves_exists. - * apply H. erewrite <- FnPreservesTag; eassumption. - * intros; subst. erewrite FnPreservesTag; eauto. - * apply EqTr2'. -Qed. - -Lemma join_map_eqv_rel - {t t' tr tr' fn} - (PreservesTags : forall it it', fn it = Some it' -> itag it = itag it') - (Success : join_nodes (map_nodes fn tr) = Some tr') - : ParentChildIn t t' tr <-> ParentChildIn t t' tr'. -Proof. - unfold ParentChildIn. - rewrite join_map_eqv_strict_rel; eauto. -Qed. - -Lemma join_map_eqv_imm_rel - {t t' tr tr' fn} - (PreservesTags : forall it it', fn it = Some it' -> itag it = itag it') - (Success : join_nodes (map_nodes fn tr) = Some tr') - : ImmediateParentChildIn t t' tr <-> ImmediateParentChildIn t t' tr'. -Proof. - generalize dependent tr'. - unfold ImmediateParentChildIn. - induction tr as [|data ? IHtr1 ? IHtr2]; intros tr' Success; simpl in *. - - inversion Success; auto. - - destruct (destruct_joined _ _ _ _ Success) as [data' [tr1' [tr2' [EqTr' [EqData' [EqTr1' EqTr2']]]]]]. - rewrite IHtr1; [|eapply EqTr1']. - rewrite IHtr2; [|eapply EqTr2']. - subst; simpl. - split; intros (H&?&?); split_and!; try done. - all: intro Hyp. - + rewrite <- join_map_preserves_exists_sibling. - * apply H. erewrite PreservesTags; eassumption. - * intros; subst. erewrite PreservesTags; eauto. - * apply EqTr2'. - + rewrite join_map_preserves_exists_sibling. - * apply H. erewrite <- PreservesTags; eassumption. - * intros; subst. erewrite PreservesTags; eauto. - * apply EqTr2'. -Qed. - Lemma insert_produces_StrictParentChild t (ins:item) (tr:tree item) : ~IsTag t ins -> StrictParentChildIn t ins.(itag) (insert_child_at tr ins (IsTag t)). @@ -326,7 +280,6 @@ Proof. intro H; contradiction. Qed. - Lemma ImmediateParentChild_of_insert_is_parent t t' (ins:item) (tr:tree item) : ¬ exists_node (IsTag (ins.(itag))) tr -> exists_node (IsTag t') tr -> @@ -367,7 +320,76 @@ Proof. eapply IHtr1'; first done. all: simpl in H1tr2,Hnt2; tauto. Qed. +(** Recall: + [map_nodes : (X -> Y) -> tree X -> tree Y] applies a function to each node. + [join_nodes : tree (option X) -> option (tree X)] collects failures. + + Our semantics are mostly expressed as a combination of these two, + in the form of [join_nodes (map_nodes faillible_function tree)]. + Therefore it is not surprising that these characterizations of + [join]+[map] are also among the most important lemmas here. *) +Lemma join_map_eqv_strict_rel t t' (tr tr':tree item) : + forall fn, + (forall it it', fn it = Some it' -> itag it = itag it') -> + join_nodes (map_nodes fn tr) = Some tr' -> + StrictParentChildIn t t' tr <-> StrictParentChildIn t t' tr'. +Proof. + intros fn FnPreservesTag Success. + generalize dependent tr'. + unfold StrictParentChildIn. + induction tr as [|data ? IHtr1 ? IHtr2]; intros tr' Success; simpl in *. + - inversion Success; auto. + - destruct (destruct_joined _ _ _ _ Success) as [data' [tr1' [tr2' [EqTr' [EqData' [EqTr1' EqTr2']]]]]]. + rewrite IHtr1; [|eapply EqTr1']. + rewrite IHtr2; [|eapply EqTr2']. + subst; simpl. + split; intro H; destruct H as [H[??]]; try repeat split; try assumption. + all: intro Hyp. + + rewrite <- join_map_preserves_exists. + * apply H. erewrite FnPreservesTag; eassumption. + * intros; subst. erewrite FnPreservesTag; eauto. + * apply EqTr2'. + + rewrite join_map_preserves_exists. + * apply H. erewrite <- FnPreservesTag; eassumption. + * intros; subst. erewrite FnPreservesTag; eauto. + * apply EqTr2'. +Qed. + +Lemma join_map_eqv_rel + {t t' tr tr' fn} + (PreservesTags : forall it it', fn it = Some it' -> itag it = itag it') + (Success : join_nodes (map_nodes fn tr) = Some tr') + : ParentChildIn t t' tr <-> ParentChildIn t t' tr'. +Proof. + unfold ParentChildIn. + rewrite join_map_eqv_strict_rel; eauto. +Qed. +Lemma join_map_eqv_imm_rel + {t t' tr tr' fn} + (PreservesTags : forall it it', fn it = Some it' -> itag it = itag it') + (Success : join_nodes (map_nodes fn tr) = Some tr') + : ImmediateParentChildIn t t' tr <-> ImmediateParentChildIn t t' tr'. +Proof. + generalize dependent tr'. + unfold ImmediateParentChildIn. + induction tr as [|data ? IHtr1 ? IHtr2]; intros tr' Success; simpl in *. + - inversion Success; auto. + - destruct (destruct_joined _ _ _ _ Success) as [data' [tr1' [tr2' [EqTr' [EqData' [EqTr1' EqTr2']]]]]]. + rewrite IHtr1; [|eapply EqTr1']. + rewrite IHtr2; [|eapply EqTr2']. + subst; simpl. + split; intros (H&?&?); split_and!; try done. + all: intro Hyp. + + rewrite <- join_map_preserves_exists_sibling. + * apply H. erewrite PreservesTags; eassumption. + * intros; subst. erewrite PreservesTags; eauto. + * apply EqTr2'. + + rewrite join_map_preserves_exists_sibling. + * apply H. erewrite <- PreservesTags; eassumption. + * intros; subst. erewrite PreservesTags; eauto. + * apply EqTr2'. +Qed. Lemma Immediate_is_StrictChildTag tg tr : HasImmediateChildTag tg tr → @@ -868,7 +890,6 @@ Proof. exists br2. split; [|assumption]. right; right; assumption. Qed. -(* FIXME: these proofs ane absolutely horrible, refactor them. *) Lemma unique_only_one_subtree {tr tg br1 br2} : tree_unique tg tr -> diff --git a/theories/tree_borrows/bor_semantics.v b/theories/tree_borrows/bor_semantics.v index e73439694e7fc88fd2d8c54c89aec8317ef49e63..79a8ea91f9592cb8cd8589606343056053108be8 100755 --- a/theories/tree_borrows/bor_semantics.v +++ b/theories/tree_borrows/bor_semantics.v @@ -17,17 +17,9 @@ From Equations Require Import Equations. From iris.prelude Require Import prelude options. From stdpp Require Export gmap. -From simuliris.tree_borrows Require Export lang_base notation tree tree_lemmas. +From simuliris.tree_borrows Require Export lang_base notation tree locations. From iris.prelude Require Import options. -Lemma decision_equiv (P Q:Prop) : - (P <-> Q) -> - Decision P -> - Decision Q. -Proof. - unfold Decision. tauto. -Defined. - (*** TREE BORROWS SEMANTICS ---------------------------------------------***) Implicit Type (c:call_id) (cids:call_id_set). @@ -351,7 +343,6 @@ Definition apply_access_perm_inner (kind:access_kind) (rel:rel_pos) (isprot:bool | AccessRead, Foreign _ => (* Foreign read. Makes [Reserved] conflicted, freezes [Active]. *) match perm with - (* FIXME: refactor *) | Reserved ResActivable => Some (Reserved (if isprot then ResConflicted else ResActivable)) | Active => if isprot then (* So that the function is commutative on all states and not just on reachable states, @@ -364,7 +355,7 @@ Definition apply_access_perm_inner (kind:access_kind) (rel:rel_pos) (isprot:bool | AccessWrite, Foreign _ => (* Foreign write. Disables everything except interior mutable [Reserved]. *) match perm with - (* TODO: remove -- this can never happen, but having it simplifies theorems. *) + (* NOTE: this can never happen, but having it simplifies theorems. *) | ReservedIM => if isprot then Some Disabled else Some $ ReservedIM | Disabled => Some Disabled | _ => Some Disabled @@ -401,11 +392,6 @@ Definition protector_is_for_call c prot := call_of_protector prot = Some c. Global Instance protector_is_for_call_dec c prot : Decision (protector_is_for_call c prot). Proof. rewrite /protector_is_for_call /call_of_protector. case_match; [case_match|]; solve_decision. Defined. -(* FIXME: This definition overlaps with logical_state.v:protected_by - We should pick one of them. If we pick this one it should be simplified - to match prot with Some (mkProtector _ c) => c in cids | None => False end. - - In practice: delete [protector_is_active]. rename [witness_protector_is_active]. fix proofs. *) Definition protector_is_active prot cids := exists c, protector_is_for_call c prot /\ call_is_active c cids. @@ -436,6 +422,14 @@ Proof. * inversion IsProt. Defined. +Lemma decision_equiv (P Q:Prop) : + (P <-> Q) -> + Decision P -> + Decision Q. +Proof. + unfold Decision. tauto. +Defined. + Global Instance protector_is_active_dec prot cids : Decision (protector_is_active prot cids). Proof. @@ -507,7 +501,6 @@ Definition tree_apply_access (* Initial permissions. *) Definition init_perms perm off sz - (* FIXME: simplify to just ø directly ? *) : permissions := mem_apply_range'_defined (fun _ => mkPerm PermInit perm) (off, sz) ∅. (* Initial tree is a single root whose default permission is [Active]. *) @@ -568,7 +561,7 @@ Definition memory_deallocate cids t range let post_write := memory_access AccessWrite cids t range tr in (* Then strong protector UB. *) let find_strong_prot : item -> option item := fun it => ( - (* FIXME: switch to plain [decide] ? *) + (* FIXME: consider switching to plain [decide] *) if bool_decide (protector_is_strong it.(iprot)) && bool_decide (protector_is_active it.(iprot) cids) then None else Some it @@ -595,7 +588,7 @@ Definition witness_transition p p' : Prop := | _, _ => False end. -(* FIXME: use builtin rtc *) +(* FIXME: using builtin reflexive transitive closure could simplify some proofs. *) Inductive witness_reach p p' : Prop := | witness_reach_refl : p = p' -> witness_reach p p' | witness_reach_step p'' : witness_transition p p'' -> witness_reach p'' p' -> witness_reach p p' @@ -613,11 +606,17 @@ Definition reach p p' : Prop := | _, _ => False end. +(* Denotes a permission that "acts like Frozen" for the purpose + of a later invariant. Concretely this contains + [Frozen], [Disabled], [Reserved ResConflicted], + which are the 3 permissions that are not affected by a foreign read, + so "acts like frozen" can mean "is allowed to coexist with shared references". *) Definition freeze_like p : Prop := reach Frozen p \/ p = Reserved ResConflicted. -(* Now we check that the two definitions are equivalent, so that the clean definition - acts as a witness for the easy-to-do-case-analysis definition *) +(* Now we check that the two definitions of reachability are equivalent, + so that the clean definition acts as a witness for the easy-to-do-case-analysis + definition *) Ltac destruct_permission := match goal with @@ -723,20 +722,26 @@ Proof. all: destruct isprot'; simpl; try auto. Qed. +(** Some important predicates on trees. *) + +(** There is a node with tag [tg]. *) Definition tree_contains tg tr : Prop := exists_node (IsTag tg) tr. +(** All nodes with tag [tg] equal [it]. + This is often useless on its own if you don't also own a [tree_contains tg]. *) Definition tree_item_determined tg it tr : Prop := every_node (fun it' => IsTag tg it' -> it' = it) tr. Notation has_tag tg := (fun it => bool_decide (IsTag tg it)) (only parsing). +(** Counting how many nodes in a tree have a certain tag. *) Definition tree_count_tg tg tr : nat := count_nodes (has_tag tg) tr. Definition tree_unique tg tr : Prop := tree_count_tg tg tr = 1. -(* TODO change to thing below *) +(** Capable of lifting any of the above predicates to [trees]. *) Definition trees_at_block prop trs blk : Prop := match trs !! blk with @@ -767,7 +772,7 @@ Definition trees_unique tg trs blk it := Definition ParentChildInBlk tg tg' trs blk := trees_at_block (ParentChildIn tg tg') trs blk. -(* FIXME: order of args *) +(* FIXME: Future refactoring: improve consistency of argument ordering *) (** Reborrow *) @@ -814,7 +819,6 @@ Definition every_tagged t (P:item -> Prop) tr : Prop := every_node (fun it => IsTag t it -> P it) tr. -(* FIXME: gmap::partial_alter ? *) Definition apply_within_trees (fn:tree item -> option (tree item)) blk : trees -> option trees := fun trs => oldtr ↠trs !! blk; @@ -832,61 +836,6 @@ Definition trees_fresh_call cid trs blk := trs !! blk = Some tr -> tree_fresh_call cid tr. -(* FIXME: this can only do strong accesses *) -Inductive bor_local_step tr cids - : bor_local_event -> tree item -> call_id_set -> Prop := - | AccessLIS kind tr' range tg - (EXISTS_TAG: tree_contains tg tr) - (ACC: memory_access kind cids tg range tr = Some tr') : - bor_local_step - tr cids - (AccessBLEvt kind tg range) - tr' cids - | InitCallLIS cid - (INACTIVE_CID : ~cid ∈ cids) - (FRESH_CID : tree_fresh_call cid tr) : - bor_local_step - tr cids - (InitCallBLEvt cid) - tr ({[cid]} ∪ cids) - | EndCallLIS cid - (EL: cid ∈ cids) : - bor_local_step - tr cids - (EndCallBLEvt cid) - tr (cids ∖ {[cid]}) - | RetagLIS tr' tgp tg pk im (cid : call_id) rk - (EL: cid ∈ cids) - (EXISTS_PARENT: tree_contains tgp tr) - (FRESH_CHILD: ~tree_contains tg tr) - (RETAG_EFFECT: create_child cids tgp tg pk im rk cid tr = Some tr') : - bor_local_step - tr cids - (RetagBLEvt tgp tg pk im cid rk) - tr' cids - (* TODO: this is missing the no-op retag for shared interiormut. *) - . - -Record seq_invariant := MkRecord { - seq_inv : tree item -> call_id_set -> Prop; -}. -Inductive bor_local_seq (invariant : seq_invariant) tr cids - : list bor_local_event -> tree item -> call_id_set -> Prop := - | bor_nil - (INV : invariant.(seq_inv) tr cids) : - bor_local_seq invariant - tr cids - [] - tr cids - | bor_cons evt tr' cids' evts tr'' cids'' - (INV : invariant.(seq_inv) tr cids) - (HEAD : bor_local_step tr cids evt tr' cids') - (REST : bor_local_seq invariant tr' cids' evts tr'' cids'') : - bor_local_seq invariant - tr cids - (evt :: evts) - tr'' cids''. - (* Traverse the entire tree and get for each tag protected by cid its currently initialized locations. Those are all the locations that we'll do a read access through, or even a write access if it is Active *) Definition tree_get_all_protected_tags_initialized_locs (cid : nat) (tr : tree item) @@ -914,7 +863,9 @@ Definition tree_access_all_protected_initialized (cids : call_id_set) (cid : nat (* finally we can combine this all *) set_fold (fun '(tg, init_locs) (tr:option (tree item)) => tr ↠tr; reader_locs tg init_locs tr) (Some tr) init_locs. -(* FIXME: IMPORTANT: don't make the access visible to children ! *) +(* WARNING: don't make the access visible to children! + You can check in `trees_access_all_protected_initialized` that we properly use + `memory_access_nonchildren_only`. *) (* Finally we read all protected initialized locations on the entire trees by folding it for each tree separately. NOTE: be careful about how other properties assume the uniqueness of tags intra- and inter- trees, @@ -929,8 +880,9 @@ Definition trees_access_all_protected_initialized (cids : call_id_set) (cid : na Inductive bor_step (trs : trees) (cids : call_id_set) (nxtp : nat) (nxtc : call_id) : event -> trees -> call_id_set -> nat -> call_id -> Prop := | AllocIS (blk : block) (off : Z) (sz : nat) + (* Memory allocation *) (FRESH : trs !! blk = None) - (NONZERO : (sz > 0)%nat) : (* FIXME: should we have an event for zero-size allocations ? *) + (NONZERO : (sz > 0)%nat) : bor_step trs cids nxtp nxtc (AllocEvt blk nxtp (off, sz)) @@ -951,14 +903,18 @@ Inductive bor_step (trs : trees) (cids : call_id_set) (nxtp : nat) (nxtc : call_ trs cids nxtp nxtc (CopyEvt alloc tg range val) trs cids nxtp nxtc - | FailedCopyIS (alloc : block) range tg +(* | FailedCopyIS (alloc : block) range tg (* Unsuccessful read access just returns poison instead of causing UB *) + (* WARNING: SB works like this, having failed reads return poison + instead of triggering UB. We can't do this for Tree Borrows. + This was a hack for SB anyway, and not having it gives a stronger result. + *) (EXISTS_TAG : trees_contain tg trs alloc) (ACC : apply_within_trees (memory_access AccessRead cids tg range) alloc trs = None) : bor_step trs cids nxtp nxtc (FailedCopyEvt alloc tg range) - trs cids nxtp nxtc + trs cids nxtp nxtc *) | WriteIS trs' (alloc : block) range tg val (* Successful write access *) (EXISTS_TAG: trees_contain tg trs alloc) @@ -981,7 +937,6 @@ Inductive bor_step (trs : trees) (cids : call_id_set) (nxtp : nat) (nxtc : call_ We want to do the read *after* the insertion so that it properly initializes the locations of the range. *) (EL: cid ∈ cids) (EXISTS_TAG: trees_contain parentt trs alloc) - (* TODO get rid of fresh_child assumption here *) (FRESH_CHILD: ~trees_contain nxtp trs alloc) (RETAG_EFFECT: apply_within_trees (create_child cids parentt nxtp pk im rk cid) alloc trs = Some trs') (READ_ON_REBOR: apply_within_trees (memory_access AccessRead cids nxtp range) alloc trs' = Some trs'') : @@ -990,9 +945,8 @@ Inductive bor_step (trs : trees) (cids : call_id_set) (nxtp : nat) (nxtc : call_ (RetagEvt alloc range parentt nxtp pk im cid rk) trs'' cids (S nxtp) nxtc | RetagNoopIS parentt (alloc : block) range pk im cid rk - (* For a retag we require that the parent exists and the introduced tag is fresh, then we do a read access. - NOTE: create_child does not read, it only inserts, so the read needs to be explicitly added. - We want to do the read *after* the insertion so that it properly initializes the locations of the range.*) + (* This is a noop retag. Some "retagging" operations don't actually do anything, + e.g. raw pointer retags. *) (EL: cid ∈ cids) (EXISTS_TAG: trees_contain parentt trs alloc) (IS_NOOP: retag_perm pk im rk = None) : @@ -1023,11 +977,29 @@ Inductive bor_step (trs : trees) (cids : call_id_set) (nxtp : nat) (nxtc : call_ trs' (cids ∖ {[c]}) nxtp nxtc . +Inductive bor_steps trs cids nxtp nxtc + : list event -> trees -> call_id_set -> nat -> call_id -> Prop := + | BorStepsDone : + bor_steps + trs cids nxtp nxtc + [] + trs cids nxtp nxtc + | BorStepsMore evt evts + trs1 cids1 nxtp1 nxtc1 + trs2 cids2 nxtp2 nxtc2 + (HEAD : bor_step trs cids nxtp nxtc evt trs1 cids1 nxtp1 nxtc1) + (REST : bor_steps trs1 cids1 nxtp1 nxtc1 evts trs2 cids2 nxtp2 nxtc2) : + bor_steps + trs cids nxtp nxtc + (evt :: evts) + trs2 cids2 nxtp2 nxtc2 + . + +(** Unit test for the tree relation definition, showing how it works *) (* conversion is magic *) Local Definition unpack_option {A:Type} (o : option A) {oo : A} (Heq : o = Some oo) : A := oo. Local Notation unwrap K := (unpack_option K eq_refl). - Local Definition initial_tree := init_tree 1 0 4. Local Definition with_one_child := unwrap (create_child ∅ 1 2 MutRef TyFrz Default 0 initial_tree). @@ -1045,6 +1017,8 @@ Local Definition with_three_children := In particular, 4 is a non-immediate child of 1, but all other child relations are immediate. *) + +(** Having constructed the above tree, we can now check that all relations are computed correctly *) (* conversion keeps being magical *) Succeed Example foo : rel_dec with_three_children 1 1 = Child This := eq_refl. Succeed Example foo : rel_dec with_three_children 1 2 = Foreign (Parent Immediate) := eq_refl. @@ -1063,7 +1037,3 @@ Succeed Example foo : rel_dec with_three_children 4 2 = Child (Strict Immediate) Succeed Example foo : rel_dec with_three_children 4 3 = Foreign Cousin := eq_refl. Succeed Example foo : rel_dec with_three_children 4 4 = Child This := eq_refl. - - - - diff --git a/theories/tree_borrows/class_instances.v b/theories/tree_borrows/class_instances.v index 70ffe1229267b71d0fad607600075f066fec526e..985b8b09679927f47dc5321c9b6c27d266d64b72 100755 --- a/theories/tree_borrows/class_instances.v +++ b/theories/tree_borrows/class_instances.v @@ -13,7 +13,6 @@ Section pure_exec. subst; intros ?; apply nsteps_once, pure_base_step_pure_step; constructor; [solve_exec_safe | solve_exec_puredet]. - (*pure_expr_step*) Global Instance pure_iota_val x (e2 : expr) (v1 : value) : PureExec True 1 (Let x (Val v1) e2) (subst' x (Val v1) e2). @@ -225,7 +224,7 @@ Section safe_reach. Global Instance safe_implies_copy_place P σ l tg (sz:nat) : SafeImplies ( (∃ v, read_mem l sz σ.(shp) = Some v ∧ trees_contain tg σ.(strs) l.1 ∧ is_Some (apply_within_trees (memory_access AccessRead σ.(scs) tg (l.2, sz)) l.1 σ.(strs)) ∧ sz ≠0%nat) ∨ (∃ v, read_mem l sz σ.(shp) = Some v ∧ sz = 0%nat) - ∨ (trees_contain tg σ.(strs) l.1 ∧ apply_within_trees (memory_access AccessRead σ.(scs) tg (l.2, sz)) l.1 σ.(strs) = None ∧ is_Some (read_mem l sz σ.(shp)))) P (Copy (Place l tg sz)) σ. + (*∨ (trees_contain tg σ.(strs) l.1 ∧ apply_within_trees (memory_access AccessRead σ.(scs) tg (l.2, sz)) l.1 σ.(strs) = None ∧ is_Some (read_mem l sz σ.(shp)))*)) P (Copy (Place l tg sz)) σ. Proof. prove_safe_implies. Qed. Global Instance safe_implies_write_val_left1 P σ v v' : diff --git a/theories/tree_borrows/defs.v b/theories/tree_borrows/defs.v index 4cd1a08e23c98fc10ecc2194fce41e9b52823a0a..8f8c276b9c52a5cf1c98627ad50089adc7a69dbc 100755 --- a/theories/tree_borrows/defs.v +++ b/theories/tree_borrows/defs.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From iris.prelude Require Export prelude. From simuliris.tree_borrows Require Export tactics notation lang bor_semantics bor_lemmas. From iris.prelude Require Import options. @@ -16,15 +12,28 @@ Definition wf_mem_tag (h: mem) (nxtp: tag) := Definition lazy_perm_wf (lp : lazy_permission) := lp.(perm) = Active → lp.(initialized) = PermInit. +(** Well-formedness constraints on items *) Record item_wf (it:item) (nxtp:tag) (nxtc:call_id) := { + (** Tag is valid *) item_tag_valid : forall tg, IsTag tg it -> (tg < nxtp)%nat; + (** Callid is valid *) item_cid_valid : forall cid, protector_is_for_call cid (iprot it) -> (cid < nxtc)%nat; + (** Permission registered as "default" can't be Active *) item_default_perm_valid : it.(initp) ≠Active; + (** Only protected items can have ReservedIM somewhere in their permissions *) item_perms_reserved_im_protected : is_Some (it.(iprot)) → ∀ off, (default (mkPerm PermLazy it.(initp)) (it.(iperm) !! off)).(perm) = ReservedIM → False; + (** Active implies initialized *) item_perms_valid : map_Forall (λ _, lazy_perm_wf) it.(iperm); + (** Current permission is reachable from initial permission. (This guarantees no Active on shared references) *) item_perm_reachable : it.(initp) ≠Disabled → map_Forall (λ k v, reach it.(initp) (perm v)) it.(iperm) }. +(** Relating the state of the current item with that of its parents. + The important properties are: + - an initialized item must have initialized parents, + - an Active item must have Active parents, + - a protected must not have Disabled parents. + *) Definition item_all_more_init itp itc := ∀ l, initialized (item_lookup itc l) = PermInit → initialized (item_lookup itp l) = PermInit. Definition parents_more_init (tr : tree item) := ∀ tg, every_child tg item_all_more_init tr. Definition item_all_more_active itp itc := ∀ l, perm (item_lookup itc l) = Active → perm (item_lookup itp l) = Active. @@ -45,9 +54,8 @@ Definition tree_items_unique (tr:tree item) := Definition tree_items_compat_nexts (tr:tree item) (nxtp:tag) (nxtc: call_id) := every_node (λ it, item_wf it nxtp nxtc) tr. - (* FIXME: rename above to just tree_items_wf *) + (* FIXME: Improve consistency of naming conventions *) -(* FIXME: consistent naming *) Definition wf_tree (tr:tree item) := tree_items_unique tr. Definition each_tree_wf (trs:trees) := @@ -69,23 +77,16 @@ Definition trees_compat_nexts (trs:trees) (nxtp:tag) (nxtc: call_id) := ∀ blk tr, trs !! blk = Some tr → tree_items_compat_nexts tr nxtp nxtc. Definition wf_non_empty (trs:trees) := ∀ blk tr, trs !! blk = Some tr → tr ≠empty. -(* -Definition wf_no_dup (α: stacks) := - ∀ l stk, α !! l = Some stk → NoDup stk. -*) + Definition wf_cid_incl (cids: call_id_set) (nxtc: call_id) := ∀ c : call_id, c ∈ cids → (c < nxtc)%nat. Definition wf_scalar t sc := ∀ t' l, sc = ScPtr l t' → t' < t. -(* mem ~ gmap loc scalar -*) - Definition same_blocks (hp:mem) (trs:trees) := dom trs =@{gset _} set_map fst (dom hp). Arguments same_blocks / _ _. -(* OLD: forall blk l, is_Some (hp !! (blk, l)) -> is_Some (trs !! blk). *) -(* FIXME: map fst (dom hp) === dom trs *) -(* FIXME: forall blk, (exists l, is_Some (hp !! (blk, l))) <-> is_Some (trs !! blk). *) +(* Formerly: map fst (dom hp) === dom trs + However this is no longer accurate. *) Definition root_invariant blk it (shp : mem) := it.(iprot) = None ∧ it.(initp) = Disabled ∧ @@ -94,7 +95,6 @@ Definition root_invariant blk it (shp : mem) := | Some (mkPerm PermLazy Disabled) | None => shp !! (blk, off) = None | _ => False end. - Definition tree_root_compatible (tr : tree item) blk shp := match tr with empty => False | branch it sib _ => root_invariant blk it shp ∧ sib = empty end. @@ -102,22 +102,29 @@ Definition tree_roots_compatible (trs : trees) shp := ∀ blk tr, trs !! blk = Some tr → tree_root_compatible tr blk shp. +(* A State is well-formed if... *) Record state_wf (s: state) := { - (*state_wf_dom : dom s.(shp) ≡ dom s.(strs); Do we care ? After all TB is very permissive about the range, so out-of-bounds UB is *always* triggered at the level of the heap, not the trees *) + (*state_wf_dom : dom s.(shp) ≡ dom s.(strs); + This was included in SB but we don't care anymore because TB + is very permissive about the range so out-of-bounds UB is *always* + triggered by `expr_semantics` not `bor_semantics`. *) + + (* The heap and the trees talk of the same allocations *) state_wf_dom : same_blocks s.(shp) s.(strs); - (*state_wf_mem_tag : wf_mem_tag s.(shp) s.(snp);*) (* FIXME: this seems to state that all pointers are wf, it should be included *) + (* Every tree is well-formed (includes uniqueness of tags) *) state_wf_tree_unq : wf_trees s.(strs); + (* The child-parent constraints relating to initialization etc. hold *) state_wf_tree_more_init : each_tree_parents_more_init s.(strs); state_wf_tree_more_active : each_tree_parents_more_active s.(strs); state_wf_tree_not_disabled : each_tree_protected_parents_not_disabled s.(scs) s.(strs); + (* Some other constraints on relations (cousins can't be simultaneously active) *) state_wf_tree_no_active_cousins : each_tree_no_active_cousins s.(scs) s.(strs); + (* "next fresh tag" is fresh. *) state_wf_tree_compat : trees_compat_nexts s.(strs) s.(snp) s.(snc); - (* state_wf_non_empty : wf_non_empty s.(strs); *) + (* Every root pointer is active *) state_wf_roots_active : tree_roots_compatible s.(strs) s.(shp); - (*state_wf_cid_no_dup : NoDup s.(scs) ;*) (* FIXME: call ids are unique, include this *) + (* "next fresh callid" is fresh. *) state_wf_cid_agree: wf_cid_incl s.(scs) s.(snc); - (* state_wf_cid_non_empty : s.(scs) ≠[]; *) - (* state_wf_no_dup : wf_no_dup σ.(cst).(sst); *) }. Definition init_state := (mkState ∅ ∅ {[O]} O 1). diff --git a/theories/tree_borrows/disjoint.v b/theories/tree_borrows/disjoint.v deleted file mode 100644 index 3931894958715690f2559c5c728a0916f18e2414..0000000000000000000000000000000000000000 --- a/theories/tree_borrows/disjoint.v +++ /dev/null @@ -1,1990 +0,0 @@ -(** This file proves some simple reorderings directly against the operational semantics - in sequential code. - - For example we prove here the fact that in any context, two adjacent read - accesses can be swapped and the resulting state is identical to the initial state. - Because these proofs use a different definition of bor_step and do not involve - parallelism, the lemmas established here are *definitely not useful* for the rest - of the project. - - Results proven here: - (1) any combination of two consecutive accesses of which - - exactly one is through a foreign pointer, - - at least one is a write, - - (sometimes with the extra restriction that one is protected) - that does not result in UB means that the two accesses must be on disjoint - ranges of memory. - (2) any pair of adjacent reads can be swapped to obtain an identical final state. - - These two combine into (1) + (2) : any two accesses of which exactly one - is foreign can be swapped (with the appropriate protector restrictions). - - I.e. this file culminates with the theorem `llvm_noalias_reorder` - that states that if `x` is - - retagged by the current function, and - - protected during the entire process, and - - not an ancestor of `y` - then for an arbitrary access `Ax` through `x` on range `Rx` and an arbitrary - access `Ay` through `y` on range `Ry`, for any initial state S, - S --[Ax(x, Rx)]-> _ --[Ay(y, Ry)]-> S' - if and only if - S --[Ay(y, Ry)]-> _ --[Ax(x, Rx)]-> S' - *) -From iris.prelude Require Import prelude options. -From stdpp Require Export gmap. -From simuliris.tree_borrows Require Import lang_base notation bor_semantics tree tree_lemmas bor_lemmas steps_preserve. -From iris.prelude Require Import options. - -(* -(* TODO do not forget *) -Check neven_see_also_the_todo_for_the_local_step_semantics_which_is_missing_a_case. - -(* Key lemma: converts the entire traversal to a per-node level. -This is applicable to every permission in the accessed range, all that's needed -to complement it should be preservation of permissions outside of said range. *) -Lemma access_effect_per_loc_within_range - {tr affected_tag access_tag pre kind cids cids' range tr' z zpre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Within : range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (Step : bor_local_step tr cids (AccessBLEvt kind access_tag range) tr' cids') - : exists post zpost, ( - let rel := rel_dec tr access_tag affected_tag in - let isprot := bool_decide (protector_is_active pre.(iprot) cids) in - apply_access_perm kind rel isprot zpre = Some zpost - /\ tree_item_determined affected_tag post tr' - /\ item_lazy_perm_at_loc post z = zpost - /\ iprot post = iprot pre - ). -Proof. - inversion Step as [???? EXISTS_TAG ACC| | | ]; subst. - (* use apply_access_spec_per_node to get info on the post permission *) - destruct (apply_access_spec_per_node Ex Unq ACC) as [post [SpecPost [ContainsPost UniquePost]]]. - (* and then it's per-tag work *) - rewrite (tree_determined_specifies_tag _ _ _ Ex Unq) in SpecPost. - option step in SpecPost as ?:tmpSpec. - injection SpecPost; intro H; subst; clear SpecPost. - (* now down to per-location *) - pose proof (mem_apply_range'_spec _ _ z _ _ tmpSpec) as ForeachSpec. - rewrite (decide_True _ _ Within) in ForeachSpec. - destruct ForeachSpec as [lazy_perm [PermExists ForeachSpec]]. - assert (default {| initialized := PermLazy; perm := initp pre |} (iperm pre !! z) = item_lazy_perm_at_loc pre z) as InitPerm. { - unfold item_lazy_perm_at_loc, item_lookup. destruct (iperm pre !! z); simpl; reflexivity. - } rewrite InitPerm in ForeachSpec. - eexists. eexists. - split; [|split; [|split]]; [|exact UniquePost|reflexivity|reflexivity]. - simpl in ForeachSpec. - rewrite ForeachSpec. - unfold item_lazy_perm_at_loc, item_lookup. - rewrite PermExists; simpl; reflexivity. -Qed. - -Lemma access_effect_per_loc_outside_range - {tr affected_tag access_tag pre kind cids cids' range tr' z zpre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Outside : ~range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (Step : bor_local_step tr cids (AccessBLEvt kind access_tag range) tr' cids') - : exists post, ( - tree_item_determined affected_tag post tr - /\ item_lazy_perm_at_loc post z = zpre - /\ iprot post = iprot pre - ). -Proof. - inversion Step as [???? EXISTS_TAG ACC| | | ]; subst. - destruct (apply_access_spec_per_node Ex Unq ACC) as [post [SpecPost [ContainsPost UniquePost]]]. - (* We now show that - (1) post has zpre at loc z - (2) post is equal to whatever item the goal refers to *) - assert (item_lazy_perm_at_loc post z = item_lazy_perm_at_loc pre z) as SamePerm. { - option step in SpecPost as ?:SpecPerms. - injection SpecPost; intros; subst; clear SpecPost. - pose proof (mem_apply_range'_spec _ _ z _ _ SpecPerms) as RangeForeach. - rewrite (decide_False _ _ Outside) in RangeForeach. - unfold item_lazy_perm_at_loc, item_lookup; simpl. - rewrite RangeForeach; reflexivity. - } - eexists. - split; [|split]; [exact Unq|reflexivity|reflexivity]. -Qed. - -(* Strategy for lemmas of the form - -Lemma _ - (Ex : tree_contains ?aff ?tr) - (Unq : tree_item_determined ?aff ?pre ?tr) - (Within : range_contains ?range ?z) - - optional: (Nonchild : ~ParentChildIn ?aff ?acc ?tr) - optional: (Child : ParentChildIn ?aff ?acc ?tr) - optional: restrictions on (perm ?pre), e.g. reachability - optional: protector_is_active (iprot ?pre) ?cids - -(Step : bor_local_step ?tr ?cids (AccessBLEvt _ ?acc ?range) ?tr' _) - : _. - -Where the conclusion can be either -* there is UB: - : False. -* there is some item in the new tree that is related to ?pre: - : exists post zpost, ( - tree_item_determined ?aff post ?tr' - /\ item_lazy_perm_at_loc post z = zpost - /\ iprot post = iprot pre - /\ ... - optional: restrictions on reachability of (perm zpost), - e.g. reach (perm ?pre) ?(perm zpost) - ). - -These lemmas can be solved by a case analysis on ?pre, which the following tactic performs *) -Ltac auto_access_event_within_range := - match goal with - (* First off, if we see an access step, we apply the key per-location lemma *) - | Ex : tree_contains ?aff ?tr, - Unq : tree_item_determined ?aff ?pre ?tr, - Within : range'_contains ?range ?z, - Step : bor_local_step ?tr _ (AccessBLEvt _ _ ?range) _ _ - |- exists _ _, _ => - destruct (access_effect_per_loc_within_range Ex Unq Within eq_refl Step) as [post[zpost[?[?[??]]]]]; - exists post, zpost; - clear Step Unq Within Ex - | Ex : tree_contains ?aff ?tr, - Unq : tree_item_determined ?aff ?pre ?tr, - Within : range'_contains ?range ?z, - Step : bor_local_step ?tr _ (AccessBLEvt _ _ ?range) _ _ - |- _ => - destruct (access_effect_per_loc_within_range Ex Unq Within eq_refl Step) as [post[zpost[?[?[??]]]]]; - clear Step Unq Within Ex - (* if we need to solve a naive_rel_dec, we look for a known one *) - | H : context[rel_dec ?tr ?acc ?aff] - |- _ => unfold rel_dec in H; - destruct (decide (ParentChildIn _ _ _)); try contradiction; - destruct (decide (ParentChildIn _ _ _)); try contradiction - (* we might need to decide protectors *) - | H : context[bool_decide (protector_is_active ?p ?cids)], - P : protector_is_active ?p ?cids - |- _ => rewrite (bool_decide_eq_true_2 _ P) in H - | H : context[bool_decide (protector_is_active ?p ?cids)] - |- _ => destruct (bool_decide (protector_is_active _ _)) - (* we'd always rather work on permissions directly than item_lazy_perm_at_loc *) - | E : item_lazy_perm_at_loc ?x ?z = _, - H : context[item_lazy_perm_at_loc ?x ?z] - |- _ => rewrite E in H - (* and then big case analysis *) - | x : lazy_permission |- _ => destruct x; simpl in * - | p : permission |- _ => destruct p as [[][]| | |]; simpl in * - | i : perm_init |- _ => destruct i; simpl in * - | H : apply_access_perm _ _ _ _ = Some _ |- _ => try (inversion H; done); clear H - (* when all the rest is done, you can split and auto *) - | |- _ => subst; try repeat split; eauto - end - . - -Lemma nonchild_write_reserved_to_disabled - {tr affected_tag access_tag pre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Nonchild : ~ParentChildIn affected_tag access_tag tr) - {cids cids' range tr' z zpre} - (Within : range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (Reach : reach (Reserved TyFrz ResActivable) (perm zpre)) - (Step : bor_local_step tr cids (AccessBLEvt AccessWrite access_tag range) tr' cids') - : exists post zpost, ( - tree_item_determined affected_tag post tr' - /\ item_lazy_perm_at_loc post z = zpost - /\ reach Disabled (perm zpost) - /\ iprot post = iprot pre - ). -Proof. do 11 auto_access_event_within_range. Qed. - -Lemma nonchild_write_any_protected_to_disabled - {tr affected_tag access_tag pre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Nonchild : ~ParentChildIn affected_tag access_tag tr) - {cids cids' range tr' z zpre} - (Protected : protector_is_active (iprot pre) cids) - (Within : range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (Step : bor_local_step tr cids (AccessBLEvt AccessWrite access_tag range) tr' cids') - : exists post zpost, ( - tree_item_determined affected_tag post tr' - /\ item_lazy_perm_at_loc post z = zpost - /\ reach Disabled (perm zpost) - /\ iprot post = iprot pre - ). -Proof. do 11 auto_access_event_within_range. Qed. - -Check neven_see_also_the_todo_for_the_local_step_semantics_which_is_missing_a_case. - -Lemma nonchild_read_active_to_frozen - {tr affected_tag access_tag pre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Nonchild : ~ParentChildIn affected_tag access_tag tr) - {cids cids' range tr' z zpre} - (Within : range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (Reach : reach Active (perm zpre)) - (Step : bor_local_step tr cids (AccessBLEvt AccessRead access_tag range) tr' cids') - : exists post zpost, ( - tree_item_determined affected_tag post tr' - /\ item_lazy_perm_at_loc post z = zpost - /\ reach Frozen (perm zpost) - /\ reach (perm zpre) (perm zpost) - ). -Proof. do 11 auto_access_event_within_range. Qed. - -Lemma child_write_frozen_to_ub - {tr affected_tag access_tag pre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Child : ParentChildIn affected_tag access_tag tr) - {cids cids' range tr' z zpre} - (Within : range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (Reach : reach Frozen (perm zpre)) - (Step : bor_local_step tr cids (AccessBLEvt AccessWrite access_tag range) tr' cids') - : False. -Proof. do 11 auto_access_event_within_range. Qed. - -Lemma child_write_protected_freeze_like_to_ub - {tr affected_tag access_tag pre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Child : ParentChildIn affected_tag access_tag tr) - {cids cids' range tr' z zpre} - (Within : range'_contains range z) - (Protected : protector_is_active (iprot pre) cids) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (FrzLike : freeze_like (perm zpre)) - (Step : bor_local_step tr cids (AccessBLEvt AccessWrite access_tag range) tr' cids') - : False. -Proof. - unfold freeze_like in FrzLike. - destruct FrzLike as [?|[?|?]]. - all: do 11 auto_access_event_within_range. -Qed. - -Lemma child_read_disabled_to_ub - {tr affected_tag access_tag pre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Child : ParentChildIn affected_tag access_tag tr) - {cids cids' range tr' z zpre} - (Within : range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (Reach : reach Disabled (perm zpre)) - (Step : bor_local_step tr cids (AccessBLEvt AccessRead access_tag range) tr' cids') - : False. -Proof. do 11 auto_access_event_within_range. Qed. - -Lemma child_write_any_to_init_active - {tr affected_tag access_tag pre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Child : ParentChildIn affected_tag access_tag tr) - {cids cids' range tr' z zpre} - (Within : range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (Step : bor_local_step tr cids (AccessBLEvt AccessWrite access_tag range) tr' cids') - : exists post zpost, ( - tree_item_determined affected_tag post tr' - /\ item_lazy_perm_at_loc post z = zpost - /\ perm zpost = Active - /\ iprot post = iprot pre - /\ initialized zpost = PermInit - ). -Proof. do 11 auto_access_event_within_range. Qed. - -Lemma child_read_any_to_init_nondis - {tr affected_tag access_tag pre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Child : ParentChildIn affected_tag access_tag tr) - {cids cids' range tr' z zpre} - (Within : range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (Step : bor_local_step tr cids (AccessBLEvt AccessRead access_tag range) tr' cids') - : exists post zpost, ( - tree_item_determined affected_tag post tr' - /\ item_lazy_perm_at_loc post z = zpost - /\ ~reach Disabled (perm zpost) - /\ iprot post = iprot pre - /\ initialized zpost = PermInit - ). -Proof. do 15 auto_access_event_within_range. Qed. - - -Lemma protected_nonchild_write_initialized_to_ub - {tr affected_tag access_tag pre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Nonchild : ~ParentChildIn affected_tag access_tag tr) - {cids cids' range tr' z zpre} - (Protected : protector_is_active (iprot pre) cids) - (Initialized : initialized (item_lazy_perm_at_loc pre z) = PermInit) - (Within : range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (NonDis : ~reach Disabled (perm zpre)) - (Step : bor_local_step tr cids (AccessBLEvt AccessWrite access_tag range) tr' cids') - : False. -Proof. do 15 auto_access_event_within_range. Qed. - -Lemma protected_nonchild_read_initialized_active_to_ub - {tr affected_tag access_tag pre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Nonchild : ~ParentChildIn affected_tag access_tag tr) - {cids cids' range tr' z zpre} - (Protected : protector_is_active (iprot pre) cids) - (Initialized : initialized (item_lazy_perm_at_loc pre z) = PermInit) - (Within : range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (Activated : perm zpre = Active) - (Step : bor_local_step tr cids (AccessBLEvt AccessRead access_tag range) tr' cids') - : False. -Proof. do 15 auto_access_event_within_range. Qed. - -(* -Definition freeze_like p : Prop := - reach Frozen p \/ p = ReservedConfl \/ p = ReservedConflMut. -*) - -Lemma protected_nonchild_read_any_to_conflicted - {tr affected_tag access_tag pre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Nonchild : ~ParentChildIn affected_tag access_tag tr) - {cids cids' range tr' z zpre} - (Protected : protector_is_active (iprot pre) cids) - (Within : range'_contains range z) - (IsPre : item_lazy_perm_at_loc pre z = zpre) - (Step : bor_local_step tr cids (AccessBLEvt AccessRead access_tag range) tr' cids') - : exists post zpost, ( - tree_item_determined affected_tag post tr' - /\ iprot post = iprot pre - /\ item_lazy_perm_at_loc post z = zpost - /\ freeze_like (perm zpost) - ). -Proof. unfold freeze_like. do 15 auto_access_event_within_range. Qed. - -(* `migrate` facilitates moving hypotheses across borrow steps. - Usage: - migrate P. - migrate P as Q. - Moves common preserved hypotheses across borrow steps. - E.g.: tree_contains is a property that is preserved by borrow steps: - `forall tg, tree_contains tg ?tr -> bor_step ?tr _ _ ?tr' _ -> tree_contains tg ?tr'`. - If you have a `H : tree_contains tg ?tr`, you can move it across the `bor_step` - using `migrate H`. - - Handles hypotheses : - - tree_contains - - ParentChildIn - - protector_is_for_call - - tree_determined - - through steps: - - bor_step - - bor_seq -*) -Ltac migrate prop dest := - lazymatch type of prop with - (* Migrate a tree_contains *) - | tree_contains ?tg ?tr => - lazymatch goal with - | Step: bor_local_step tr _ _ _ _ |- _ => - pose proof (bor_local_step_preserves_contains prop Step) as dest - | Seq : bor_local_seq _ tr _ _ _ _ |- _ => - pose proof (bor_local_seq_last_contains prop (bor_local_seq_forget Seq)) as dest - end - (* Migrate a parent-child relation *) - | context [ParentChildIn ?tg ?tg' ?tr] => - lazymatch goal with - | Step : bor_local_step tr _ _ _ _, - Ex : tree_contains tg tr, - Ex' : tree_contains tg' tr - |- _ => - pose proof prop as dest; - rewrite (bor_local_step_eqv_rel Ex Ex' Step) in dest - | Seq : bor_local_seq _ tr _ _ _ _, - Ex : tree_contains tg tr, - Ex' : tree_contains tg' tr - |- _ => - pose proof prop as dest; - rewrite (bor_local_seq_last_eqv_rel Ex Ex' (bor_local_seq_forget Seq)) in dest - end - (* Migrate info on a protector *) - | context [protector_is_for_call _ ?old] => - lazymatch goal with - | ACC: old = ?new |- _ => - pose proof prop as dest; - rewrite ACC in dest - | ACC: ?new = old |- _ => - pose proof prop as dest; - rewrite <- ACC in prop - end - (* Migrate a tree_item_determined (lossy) *) - | tree_item_determined ?tg _ ?tr => - lazymatch goal with - | Seq : bor_local_seq _ tr _ _ _ _, - Ex : tree_contains tg tr - |- _ => - pose proof (bor_local_seq_last_determined Ex prop (bor_local_seq_forget Seq)) as dest - end - (* failed *) - | ?other => - idtac prop " of type " other " cannot be migrated" - end. - -Tactic Notation "migrate" constr(prop) "as" ident(dest) := - migrate prop dest. -Tactic Notation "migrate" constr(prop) := - let tmp := fresh "tmp" in - migrate prop as tmp; - clear prop; - rename tmp into prop. - -(* `forget` makes a name fresh again - Usage: - forget x. -*) -Ltac forget x := - repeat match goal with - | H: context [x] |- _ => clear H - end; - clear x. - -(* `created_determined`, `created_protected`, and `created_nonparent` know the properties of items produced by `create_new_item` - Usage: - created tg determined as [tgExists tgUnique]. - created tg protected as tgProtected. - created tg nonparent of tg' as Unrelated. - If you have sufficient hypotheses, these will produce proofs for - - tree_contains tg ?tr - - tree_item_determined tg (create_new_item tg _) ?tr - - protector_is_for_call (iprot (create_new_item tg _)) _ - - ~ParentChildIn tg tg' ?tr - respectively. -*) -Ltac created_determined tg bindEx bindUnq := - match goal with - | Rebor : bor_local_step ?tr _ (RetagBLEvt _ tg _ _ _) _ _ |- _ => - pose proof (bor_local_step_retag_produces_contains_determined Rebor) as [bindEx bindUnq] - end. - -Tactic Notation "created" constr(tg) "determined" "as" "[" ident(ex) ident(uq) "]" := - created_determined tg ex uq. -Tactic Notation "created" constr(tg) "determined" := - let ex := fresh "Exists" in - let uq := fresh "Unique" in - created_determined tg ex uq. - -Ltac created_protected tg dest := - let newp := fresh "newp" in - lazymatch goal with - | _ : context [create_new_item tg ?pk FnEntry ?cid] - |- _ => - assert (protector_is_for_call cid (iprot (create_new_item tg pk FnEntry cid))) as dest by constructor - end. - -Tactic Notation "created" constr(tg) "protected" "as" ident(prot) := - created_protected tg prot. -Tactic Notation "created" constr(tg) "protected" := - let prot := fresh "Protected" in - created_protected tg prot. - -Ltac created_nonparent tg other dest := - match goal with - | Rebor : bor_local_step ?tr _ (RetagBLEvt _ tg _ _ _) _ _, - Exother : tree_contains other ?tr - |- _ => - pose proof (bor_local_step_retag_order_nonparent Exother Rebor) as dest - end. - -Tactic Notation "created" constr(tg) "nonparent" "of" constr(other) "as" ident(dest) := - created_nonparent tg other dest. -Tactic Notation "created" constr(tg) "nonparent" "of" constr(other) := - let unrel := fresh "Unrelated" in - created_nonparent tg other unrel. - -(* Incomplete heuristics to derive `reach _ _` *) -Ltac solve_reachability := - let p := fresh "perm" in - multimatch goal with - | |- reach _ _ => assumption - | |- reach _ _ => eapply reach_reflexive; done - | |- reach _ (perm (item_lazy_perm_at_loc (create_new_item _ _ _ _) _)) => eapply create_new_item_perm_prop - (* transitivity hints *) - | |- reach Frozen ?p => apply (reach_transitive Frozen Disabled p); [done|] - end. - -(* `specialize` on steroids. - `pose replace` is a generalization of `specialize`: - `pose replace H with @ x` is mostly equivalent to `specialize H with x`. - - What it offers in addition is - - specialization of Prop arguments - - arbitrary order of arguments (if the one you need is not there, add it below as a Tactic Notation) - - `pose replace H with P Q @ R` - will replace the hypothesis `H` with `(P Q H R)` -*) -Ltac squash new old := try clear old; rename new into old. -Ltac xspecialize name term := - let tmp := fresh "tmp" in - pose proof term as tmp; - squash tmp name. -Tactic Notation "pose" "replace" constr(target) "with" uconstr(a) uconstr(b) := xspecialize target (a b). -Tactic Notation "pose" "replace" constr(target) "with" "@" uconstr(b) := xspecialize target (target b). -Tactic Notation "pose" "replace" constr(target) "with" "@" uconstr(b) uconstr(c) := xspecialize target (target b c). -Tactic Notation "pose" "replace" constr(target) "with" uconstr(a) uconstr(b) uconstr(c) uconstr(d) "@" := xspecialize target (a b c d target). -Tactic Notation "pose" "replace" constr(target) "with" uconstr(a) uconstr(b) uconstr(c) "@" uconstr(d) := xspecialize target (a b c target d). -Tactic Notation "pose" "replace" constr(target) "with" uconstr(a) uconstr(b) uconstr(c) uconstr(d) "@" uconstr(f) := xspecialize target (a b c d target f). -Tactic Notation "pose" "replace" constr(target) "with" uconstr(a) uconstr(b) uconstr(c) uconstr(d) uconstr(e) "@" uconstr(g) := xspecialize target (a b c d e target g). - -Lemma fwrite_cwrite_disjoint - {tg tg' range1 range2 tgp tr0 tr0' tr1 tr1' tr2 tr2' cid cids0 cids0' cids1 cids1' cids2 cids2' pk rk} - (Ex : tree_contains tg tr0) - (ResReach : reach (Reserved TyFrz ResActivable) (pointer_kind_to_perm pk)) - (Retag0 : bor_local_step tr0 cids0 (RetagBLEvt tgp tg' pk cid rk) tr0' cids0') - (Seq01 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr0' cids0' l tr1 cids1) - (Write1 : bor_local_step tr1 cids1 (AccessBLEvt AccessWrite tg range1) tr1' cids1') - (Seq12 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr1' cids1' l tr2 cids2) - (Write2 : bor_local_step tr2 cids2 (AccessBLEvt AccessWrite tg' range2) tr2' cids2') - : ~exists z, range'_contains range1 z /\ range'_contains range2 z. -Proof. - intros [z [RContains1 RContains2]]. - (* reborrow step *) - created tg' determined as [Ex' Unq']. - created tg' nonparent of tg as Unrelated. - migrate Ex. - forget tr0. - - (* opaque seq *) - destruct Seq01 as [evts01 Seq01]. - assert (reach (Reserved TyFrz ResActivable) (perm (item_lazy_perm_at_loc (create_new_item tg' pk rk cid) z))) as ResReach1 by solve_reachability. - migrate Unrelated. - pose replace ResReach1 with bor_local_seq_last_backward_reach Ex' Unq' @ Seq01. - migrate Unq'; destruct Unq' as [post [Unq' _]]. - pose replace ResReach1 with @ post Unq'. - migrate Ex'. - forget tr0'. - - (* write step 1 *) - rename post into pre. - destruct (nonchild_write_reserved_to_disabled Ex' Unq' Unrelated RContains1 eq_refl ltac:(solve_reachability) Write1) - as [post [zpost [Unq'Post [PermPost [DisPost ProtPost]]]]]. - migrate Ex'. - forget tr1. - forget pre. - - (* opaque seq *) - subst. - rename Unq'Post into Unq'. - rename post into pre. - destruct Seq12 as [evts12 Seq12]. - pose replace DisPost with bor_local_seq_last_backward_reach Ex' Unq' @ Seq12. - migrate Unq'; destruct Unq' as [post [Unq' _]]. - pose replace DisPost with @ post Unq'. - migrate Ex'. - - (* write step 2 *) - destruct (child_write_frozen_to_ub Ex' Unq' ltac:(left; done) RContains2 eq_refl ltac:(repeat solve_reachability) Write2). -Qed. - -Lemma fwrite_cread_disjoint - {tg tg' pk rk range1 range2 tgp tr0 tr0' tr1 tr1' tr2 tr2' cid cids0 cids0' cids1 cids1' cids2 cids2'} - (Ex : tree_contains tg tr0) - (ResReach : reach (Reserved TyFrz ResActivable) (pointer_kind_to_perm pk)) - (Retag0 : bor_local_step tr0 cids0 (RetagBLEvt tgp tg' pk cid rk) tr0' cids0') - (Seq01 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr0' cids0' l tr1 cids1) - (Write1 : bor_local_step tr1 cids1 (AccessBLEvt AccessWrite tg range1) tr1' cids1') - (Seq12 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr1' cids1' l tr2 cids2) - (Read2 : bor_local_step tr2 cids2 (AccessBLEvt AccessRead tg' range2) tr2' cids2') - : ~exists z, range'_contains range1 z /\ range'_contains range2 z. -Proof. - move=> [z [RContains1 RContains2]]. - (* reborrow step *) - created tg' determined as [Ex' Unq']. - created tg' nonparent of tg as Unrelated. - migrate Ex. - forget tr0. - - (* opaque seq *) - destruct Seq01 as [evts01 Seq01]. - assert (reach (Reserved TyFrz ResActivable) (perm (item_lazy_perm_at_loc (create_new_item tg' pk rk cid) z))) as ResReach1 by solve_reachability. - migrate Unrelated. - pose replace ResReach1 with bor_local_seq_last_backward_reach Ex' Unq' @ Seq01. - migrate Unq'; destruct Unq' as [post [Unq' _]]. - pose replace ResReach1 with @ post Unq'. - migrate Ex'. - forget tr0'. - - (* write step 1 *) - rename post into pre. - destruct (nonchild_write_reserved_to_disabled - Ex' Unq' - Unrelated - RContains1 eq_refl - ltac:(solve_reachability) - Write1 - ) as [post [zpost [Unq'Post [PermPost [DisPost ProtPost]]]]]. - migrate Ex'. - forget tr1. - forget pre. - - (* opaque seq *) - subst. - rename Unq'Post into Unq'. - rename post into pre. - destruct Seq12 as [evts12 Seq12]. - pose replace DisPost with bor_local_seq_last_backward_reach Ex' Unq' @ Seq12. - migrate Unq'; destruct Unq' as [post [Unq' _]]. - pose replace DisPost with @ post Unq'. - migrate Ex'. - - (* read step 2 *) - destruct (child_read_disabled_to_ub - Ex' Unq' - ltac:(left; reflexivity) - RContains2 eq_refl - ltac:(solve_reachability) - Read2). -Qed. - -Lemma protected_fwrite_cwrite_disjoint - {tg tg' pk range1 range2 tgp tr0 tr0' tr1 tr1' tr2 tr2' cid cids0 cids0' cids1 cids1' cids2 cids2'} - (Ex : tree_contains tg tr0) - (Retag0 : bor_local_step tr0 cids0 (RetagBLEvt tgp tg' pk cid FnEntry) tr0' cids0') - (Seq01 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr0' cids0' l tr1 cids1) - (Call : call_is_active cid cids1) - (Write1 : bor_local_step tr1 cids1 (AccessBLEvt AccessWrite tg range1) tr1' cids1') - (Seq12 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr1' cids1' l tr2 cids2) - (Write2 : bor_local_step tr2 cids2 (AccessBLEvt AccessWrite tg' range2) tr2' cids2') - : ~exists z, range'_contains range1 z /\ range'_contains range2 z. -Proof. - intros [z [RContains1 RContains2]]. - (* reborrow step *) - created tg' determined as [Ex' Unq']. - created tg' nonparent of tg as Unrelated. - migrate Ex. - forget tr0. - - (* opaque seq *) - destruct Seq01 as [evts01 Seq01]. - migrate Unrelated. - migrate Unq'; destruct Unq' as [post [Unq' Prot']]. - migrate Ex'. - forget tr0'. - - (* write step 1 *) - rename post into pre. - assert (protector_is_active (iprot pre) cids1) as Protected by (eexists; split; [|eassumption]; rewrite -Prot'; constructor). - destruct (nonchild_write_any_protected_to_disabled Ex' Unq' Unrelated Protected RContains1 eq_refl Write1) - as [post [zpost [Unq'Post [PermPost [DisPost ProtPost]]]]]. - migrate Ex'. - forget tr1. - forget pre. - - (* opaque seq *) - subst. - rename Unq'Post into Unq'. - rename post into pre. - destruct Seq12 as [evts12 Seq12]. - pose replace DisPost with bor_local_seq_last_backward_reach Ex' Unq' @ Seq12. - migrate Unq'; destruct Unq' as [post [Unq' _]]. - pose replace DisPost with @ post Unq'. - migrate Ex'. - - (* write step 2 *) - destruct (child_write_frozen_to_ub Ex' Unq' ltac:(left; done) RContains2 eq_refl ltac:(repeat solve_reachability) Write2). -Qed. - -Lemma protected_fwrite_cread_disjoint - {tg tg' pk range1 range2 tgp tr0 tr0' tr1 tr1' tr2 tr2' cid cids0 cids0' cids1 cids1' cids2 cids2'} - (Ex : tree_contains tg tr0) - (Retag0 : bor_local_step tr0 cids0 (RetagBLEvt tgp tg' pk cid FnEntry) tr0' cids0') - (Seq01 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr0' cids0' l tr1 cids1) - (Call : call_is_active cid cids1) - (Write1 : bor_local_step tr1 cids1 (AccessBLEvt AccessWrite tg range1) tr1' cids1') - (Seq12 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr1' cids1' l tr2 cids2) - (Read2 : bor_local_step tr2 cids2 (AccessBLEvt AccessRead tg' range2) tr2' cids2') - : ~exists z, range'_contains range1 z /\ range'_contains range2 z. -Proof. - move=> [z [RContains1 RContains2]]. - (* reborrow step *) - created tg' determined as [Ex' Unq']. - created tg' nonparent of tg as Unrelated. - migrate Ex. - forget tr0. - - (* opaque seq *) - destruct Seq01 as [evts01 Seq01]. - migrate Unrelated. - migrate Unq'; destruct Unq' as [post [Unq' Prot']]. - migrate Ex'. - forget tr0'. - - (* write step 1 *) - rename post into pre. - assert (protector_is_active (iprot pre) cids1) as Protected by (eexists; split; [|eassumption]; rewrite -Prot'; constructor). - destruct (nonchild_write_any_protected_to_disabled - Ex' Unq' - Unrelated - Protected RContains1 - eq_refl - Write1 - ) as [post [zpost [Unq'Post [PermPost [DisPost ProtPost]]]]]. - migrate Ex'. - forget tr1. - forget pre. - - (* opaque seq *) - subst. - rename Unq'Post into Unq'. - rename post into pre. - destruct Seq12 as [evts12 Seq12]. - pose replace DisPost with bor_local_seq_last_backward_reach Ex' Unq' @ Seq12. - migrate Unq'; destruct Unq' as [post [Unq' _]]. - pose replace DisPost with @ post Unq'. - migrate Ex'. - - (* read step 2 *) - destruct (child_read_disabled_to_ub - Ex' Unq' - ltac:(left; reflexivity) - RContains2 eq_refl - ltac:(solve_reachability) - Read2). -Qed. - - -Lemma activated_fread_cwrite_disjoint - {tg tg' pk rk range1 range2 range3 tgp tr0 tr0' tr1 tr1' tr2 tr2' tr3 tr3' cid cids0 cids0' cids1 cids1' cids2 cids2' cids3 cids3'} - (Ex : tree_contains tg tr0) - (Retag0 : bor_local_step tr0 cids0 (RetagBLEvt tgp tg' pk cid rk) tr0' cids0') - (Seq01 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr0' cids0' l tr1 cids1) - (Write1 : bor_local_step tr1 cids1 (AccessBLEvt AccessWrite tg' range1) tr1' cids1') - (Seq12 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr1' cids1' l tr2 cids2) - (Read2 : bor_local_step tr2 cids2 (AccessBLEvt AccessRead tg range2) tr2' cids2') - (Seq23 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr2' cids2' l tr3 cids3) - (Write3 : bor_local_step tr3 cids3 (AccessBLEvt AccessWrite tg' range3) tr3' cids3') - : ~exists z, range'_contains range1 z /\ range'_contains range2 z /\ range'_contains range3 z. -Proof. - move=> [z [RContains1 [RContains2 RContains3]]]. - (* reborrow step *) - created tg' determined as [Ex' Unq']. - created tg' nonparent of tg as Unrelated. - migrate Ex. - forget tr0. - - (* opaque seq *) - destruct Seq01 as [evts01 Seq01]. - migrate Unrelated. - migrate Unq'; destruct Unq' as [post [Unq' _]]. - migrate Ex'. - migrate Ex. - forget tr0'. - - (* write step 1 *) - rename post into pre. - destruct (child_write_any_to_init_active - Ex' Unq' - ltac:(left; reflexivity) - RContains1 eq_refl - Write1 - ) as [post [zpost [Unq'Post [PermPost [ActPost _]]]]]. - migrate Unrelated. - migrate Ex'. - migrate Ex. - forget tr1. - forget pre. - assert (reach Active (perm zpost)) as ActReachPost by solve_reachability. - - (* opaque seq *) - subst. - rename Unq'Post into Unq'. - rename post into pre. - destruct Seq12 as [evts12 Seq12]. - migrate Unrelated. - pose replace ActReachPost with bor_local_seq_last_backward_reach Ex' Unq' @ Seq12. - migrate Unq'; destruct Unq' as [post [Unq' _]]. - pose replace ActReachPost with @ post Unq'. - migrate Ex'. - forget pre. - - (* read step 2 *) - rename post into pre. - rename ActReachPost into ActReachPre. - destruct (nonchild_read_active_to_frozen - Ex' Unq' - Unrelated - RContains2 eq_refl - ltac:(solve_reachability) - Read2) as [post [zpost [Unq'Post [PermPost [FrzReachPost PreReachPost]]]]]. - migrate Ex'. - forget tr2. - forget pre. - - (* opaque seq *) - subst. - rename Unq'Post into Unq'. - rename post into pre. - destruct Seq23 as [evts23 Seq23]. - pose replace FrzReachPost with bor_local_seq_last_backward_reach Ex' Unq' @ Seq23. - migrate Unq'; destruct Unq' as [post [Unq' _]]. - pose replace FrzReachPost with @ post Unq'. - migrate Ex'. - - (* write step 3 *) - destruct (child_write_frozen_to_ub - Ex' Unq' - ltac:(left; reflexivity) - RContains3 eq_refl - ltac:(solve_reachability) - Write3). -Qed. - -Lemma protected_cwrite_fwrite_disjoint - {tg tg' cid pk range1 range2 tgp tr0 tr0' tr1 tr1' tr2 tr2' cids0 cids0' cids1 cids1' cids2 cids2'} - (Ex : tree_contains tg tr0) - (Retag0 : bor_local_step tr0 cids0 (RetagBLEvt tgp tg' pk cid FnEntry) tr0' cids0') - (Seq01 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr0' cids0' l tr1 cids1) - (Write1 : bor_local_step tr1 cids1 (AccessBLEvt AccessWrite tg' range1) tr1' cids1') - (Seq12 : exists l, bor_local_seq {|seq_inv:=fun _ cids => call_is_active cid cids|} tr1' cids1' l tr2 cids2) - (Write2 : bor_local_step tr2 cids2 (AccessBLEvt AccessWrite tg range2) tr2' cids2') - : ~exists z, range'_contains range1 z /\ range'_contains range2 z. -Proof. - move=> [z [RContains1 RContains2]]. - (* reborrow step *) - created tg' determined as [Ex' Unq']. - created tg' protected as Protected. - created tg' nonparent of tg as Unrelated. - migrate Ex. - forget tr0. - - (* opaque seq *) - destruct Seq01 as [evts01 Seq01]. - migrate Unrelated. - migrate Unq'; destruct Unq' as [post [Unq' Prot']]. - migrate Ex'. - migrate Ex. - forget tr0'. - - (* write step 1 *) - subst. - rename post into pre. - destruct (child_write_any_to_init_active - Ex' Unq' ltac:(left; reflexivity) - RContains1 eq_refl - Write1 - ) as [post [zpost [Unq'Post [PermPost [ActPost [ProtPost InitPost]]]]]]. - migrate Unrelated. - migrate Ex. - migrate Ex'. - migrate Protected. - rewrite <- ProtPost in Protected. - forget tr1. - forget pre. - - (* opaque seq *) - subst. - rename Unq'Post into Unq'. - rename post into pre. - destruct Seq12 as [evts12 Seq12]. - migrate Unrelated. - assert (bor_local_seq - {|seq_inv:=fun tr cids => - (forall it, - tree_item_determined tg' it tr -> - initialized (item_lazy_perm_at_loc it z) = PermInit) - /\ call_is_active cid cids|} - tr1' cids1' evts12 tr2 cids2) as GenActPost. { - pose proof (bor_local_seq_always_perminit Ex' Unq' InitPost (bor_local_seq_forget Seq12)) as Seq12Init. - eapply seq_always_build_weaken; [|exact (seq_always_merge Seq12Init Seq12)]. - simpl. move=> ?? H; split; edestruct H; eauto. - } - pose replace ActPost with protected_during_seq_last_stays_active Ex' Unq' eq_refl Protected @ GenActPost. - migrate Unq'; destruct Unq' as [post [Unq' ProtPost]]. - pose replace ActPost with @ post Unq'. - migrate Ex'. - migrate Protected. - forget pre. - - (* write step 2 *) - subst. - pose proof (seq_always_destruct_last GenActPost) as [Init Call]. - destruct (protected_nonchild_write_initialized_to_ub - Ex' Unq' Unrelated - ltac:(eexists; split; [exact Protected|exact Call]) - (Init _ Unq') - RContains2 eq_refl - ltac:(rewrite ActPost; eauto) - Write2). -Qed. - -Lemma protected_cread_fwrite_disjoint - {tg tg' cid pk range1 range2 tgp tr0 tr0' tr1 tr1' tr2 tr2' cids0 cids0' cids1 cids1' cids2 cids2'} - (Ex : tree_contains tg tr0) - (Retag0 : bor_local_step tr0 cids0 (RetagBLEvt tgp tg' pk cid FnEntry) tr0' cids0') - (Seq01 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr0' cids0' l tr1 cids1) - (Read1 : bor_local_step tr1 cids1 (AccessBLEvt AccessRead tg' range1) tr1' cids1') - (Seq12 : exists l, bor_local_seq {|seq_inv:=fun _ cids => call_is_active cid cids|} tr1' cids1' l tr2 cids2) - (Write2 : bor_local_step tr2 cids2 (AccessBLEvt AccessWrite tg range2) tr2' cids2') - : ~exists z, range'_contains range1 z /\ range'_contains range2 z. -Proof. - move=> [z [RContains1 RContains2]]. - (* reborrow step *) - created tg' determined as [Ex' Unq']. - created tg' protected as Protected. - created tg' nonparent of tg as Unrelated. - migrate Ex. - forget tr0. - - (* opaque seq *) - destruct Seq01 as [evts01 Seq01]. - migrate Unrelated. - migrate Unq'; destruct Unq' as [post [Unq' Prot']]. - migrate Ex'. - migrate Ex. - forget tr0'. - - (* write step 1 *) - subst. - rename post into pre. - destruct (child_read_any_to_init_nondis - Ex' Unq' ltac:(left; reflexivity) - RContains1 eq_refl Read1 - ) as [post [zpost [Unq'Post [PermPost [DisUnreachPost [ProtPost InitPost]]]]]]. - migrate Unrelated. - migrate Ex. - migrate Ex'. - migrate Protected. - rewrite <- ProtPost in Protected. - forget tr1. - forget pre. - - (* opaque seq *) - subst. - rename Unq'Post into Unq'. - rename post into pre. - destruct Seq12 as [evts12 Seq12]. - migrate Unrelated. - assert (bor_local_seq - {|seq_inv:=fun tr cids => - (forall it, - tree_item_determined tg' it tr -> - initialized (item_lazy_perm_at_loc it z) = PermInit) - /\ call_is_active cid cids|} - tr1' cids1' evts12 tr2 cids2) as GenNonDisPost. { - pose proof (bor_local_seq_always_perminit Ex' Unq' InitPost (bor_local_seq_forget Seq12)) as Seq12Init. - eapply seq_always_build_weaken; [|exact (seq_always_merge Seq12Init Seq12)]. - simpl. move=> ?? [??]; auto. - } - pose replace DisUnreachPost with protected_during_seq_last_stays_nondis Ex' Unq' eq_refl Protected @ GenNonDisPost. - migrate Unq'; destruct Unq' as [post [Unq' ProtPost]]. - pose replace DisUnreachPost with @ post Unq'. - migrate Ex'. - migrate Protected. - forget pre. - - subst. - pose proof (seq_always_destruct_last GenNonDisPost) as [Init Call]. - destruct (protected_nonchild_write_initialized_to_ub - Ex' Unq' Unrelated - ltac:(eexists; split; [exact Protected|exact Call]) - (Init _ Unq') RContains2 eq_refl DisUnreachPost Write2). -Qed. - -Lemma protected_cwrite_fread_disjoint - {tg tg' cid pk range1 range2 tgp tr0 tr0' tr1 tr1' tr2 tr2' cids0 cids0' cids1 cids1' cids2 cids2'} - (Ex : tree_contains tg tr0) - (Retag0 : bor_local_step tr0 cids0 (RetagBLEvt tgp tg' pk cid FnEntry) tr0' cids0') - (Seq01 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr0' cids0' l tr1 cids1) - (Write1 : bor_local_step tr1 cids1 (AccessBLEvt AccessWrite tg' range1) tr1' cids1') - (Seq12 : exists l, bor_local_seq {|seq_inv:=fun _ cids => call_is_active cid cids|} tr1' cids1' l tr2 cids2) - (Read2 : bor_local_step tr2 cids2 (AccessBLEvt AccessRead tg range2) tr2' cids2') - : ~exists z, range'_contains range1 z /\ range'_contains range2 z. -Proof. - move=> [z [RContains1 RContains2]]. - (* reborrow step *) - created tg' determined as [Ex' Unq']. - created tg' protected as Protected. - created tg' nonparent of tg as Unrelated. - migrate Ex. - forget tr0. - - (* opaque seq *) - destruct Seq01 as [evts01 Seq01]. - migrate Unrelated. - migrate Unq'; destruct Unq' as [post [Unq' Prot']]. - migrate Ex'. - migrate Ex. - forget tr0'. - - (* write step 1 *) - subst. - rename post into pre. - destruct (child_write_any_to_init_active - Ex' Unq' ltac:(left; reflexivity) - RContains1 eq_refl Write1) as [post [zpost [Unq'Post [PermPost [ActPost [ProtPost InitPost]]]]]]. - migrate Unrelated. - migrate Ex. - migrate Ex'. - migrate Protected. - rewrite <- ProtPost in Protected. - forget tr1. - forget pre. - - (* opaque seq *) - subst. - rename Unq'Post into Unq'. - rename post into pre. - destruct Seq12 as [evts12 Seq12]. - migrate Unrelated. - assert (bor_local_seq - {|seq_inv:=fun tr cids => - (forall it, - tree_item_determined tg' it tr -> - initialized (item_lazy_perm_at_loc it z) = PermInit) - /\ call_is_active cid cids|} - tr1' cids1' evts12 tr2 cids2) as GenActPost. { - pose proof (bor_local_seq_always_perminit Ex' Unq' InitPost (bor_local_seq_forget Seq12)) as Seq12Init. - eapply seq_always_build_weaken; [|exact (seq_always_merge Seq12Init Seq12)]. - simpl. move=> ?? [??]; auto. - } - pose replace ActPost with protected_during_seq_last_stays_active Ex' Unq' eq_refl Protected @ GenActPost. - migrate Unq'; destruct Unq' as [post [Unq' ProtPost]]. - pose replace ActPost with @ post Unq'. - migrate Ex'. - migrate Protected. - forget pre. - - (* read step 2 *) - subst. - pose proof (seq_always_destruct_last GenActPost) as [Init Call]. - destruct (protected_nonchild_read_initialized_active_to_ub - Ex' Unq' Unrelated - ltac:(eexists; split; [exact Protected|exact Call]) - (Init _ Unq') RContains2 eq_refl ActPost Read2). -Qed. - -Lemma protected_fread_cwrite_disjoint - {tg tg' cid pk range1 range2 tgp tr0 tr0' tr1 tr1' tr2 tr2' cids0 cids0' cids1 cids1' cids2 cids2'} - (Ex : tree_contains tg tr0) - (Retag0 : bor_local_step tr0 cids0 (RetagBLEvt tgp tg' pk cid FnEntry) tr0' cids0') - (Seq01 : exists l, bor_local_seq {|seq_inv:=fun _ _ => True|} tr0' cids0' l tr1 cids1) - (Call1 : call_is_active cid cids1) - (Read1 : bor_local_step tr1 cids1 (AccessBLEvt AccessRead tg range1) tr1' cids1') - (Seq12 : exists l, bor_local_seq {|seq_inv:=fun _ cids => call_is_active cid cids|} tr1' cids1' l tr2 cids2) - (Write2 : bor_local_step tr2 cids2 (AccessBLEvt AccessWrite tg' range2) tr2' cids2') - : ~exists z, range'_contains range1 z /\ range'_contains range2 z. -Proof. - move=> [z [RContains1 RContains2]]. - (* reborrow step *) - created tg' determined as [Ex' Unq']. - created tg' protected as Protected. - created tg' nonparent of tg as Unrelated. - migrate Ex. - forget tr0. - - (* opaque seq *) - destruct Seq01 as [evts01 Seq01]. - migrate Unrelated. - migrate Unq'; destruct Unq' as [post [Unq' Prot']]. - migrate Protected. - migrate Ex'. - migrate Ex. - forget tr0'. - - (* write step 1 *) - subst. - rename post into pre. - destruct (protected_nonchild_read_any_to_conflicted - Ex' Unq' - Unrelated - ltac:(eexists; split; [exact Protected|exact Call1]) - RContains1 eq_refl Read1 - ) as [post [zpost [Unq'Post [ProtPost [PermPost FrzLikePost]]]]]. - migrate Ex'. - rewrite <- ProtPost in Protected. - forget tr1. - forget pre. - - (* opaque seq *) - subst. - rename Unq'Post into Unq'. - rename post into pre. - destruct Seq12 as [evts12 Seq12]. - pose replace FrzLikePost with bor_local_seq_last_protected_freeze_like Ex' Unq' Protected @ Seq12. - migrate Unq'; destruct Unq' as [post [Unq' Unq'Prot]]. - pose replace FrzLikePost with @ post Unq'. - pose proof (seq_always_destruct_last Seq12) as Prot2; simpl in Prot2. - destruct FrzLikePost as [ProtPost FrzLike]. - migrate Ex'. - - (* read step 2 *) - destruct (child_write_protected_freeze_like_to_ub - Ex' Unq' - ltac:(left; reflexivity) - RContains2 ltac:(exists cid; split; [exact ProtPost|exact Prot2]) eq_refl - FrzLike - Write2). -Qed. - -(* rename bor_local_seq: bor_local_steps *) -(* ghost state, ressource algebras, invariants *) - -Definition disjoint' range1 range2 := ~exists z, range'_contains range1 z /\ range'_contains range2 z. - -Lemma llvm_retagx_opaque_writey_writex_disjoint - {tg_x tg_y tg_xparent tr_initial tr_final cids_initial cids_final cid pk opaque range_x range_y} - (AlreadyExists_y : tree_contains tg_y tr_initial) - (Seq : bor_local_seq - {|seq_inv:=fun _ cids => call_is_active cid cids|} - tr_initial cids_initial - ( - [RetagBLEvt tg_xparent tg_x pk cid FnEntry] - ++ opaque - ++ [AccessBLEvt AccessWrite tg_y range_y] - ++ [AccessBLEvt AccessWrite tg_x range_x] - ) - tr_final cids_final) - : disjoint' range_y range_x. -Proof. - destruct (proj1 bor_local_seq_split Seq) as [?[?[SeqRetag Seq']]]; clear Seq. - destruct (proj1 bor_local_seq_split Seq') as [?[?[SeqOpaque Seq'']]]; clear Seq'. - destruct (proj1 bor_local_seq_split Seq'') as [?[?[SeqWritey SeqWritex]]]; clear Seq''. - inversion SeqRetag as [|?????? INV1 HEAD1 REST1]. subst. - inversion SeqWritey as [|?????? INV2 HEAD2 REST2]; subst. - inversion SeqWritex as [|?????? INV3 HEAD3 REST3]; subst. - inversion REST1; subst. - inversion HEAD1 as [| | |???????? COMPAT_CID1]. - eapply protected_fwrite_cwrite_disjoint. - - exact AlreadyExists_y. - - exact HEAD1. - - exists opaque. exact (bor_local_seq_forget SeqOpaque). - - exact INV2. - - exact HEAD2. - - exists []. exact (bor_local_seq_forget REST2). - - exact HEAD3. -Qed. - -Lemma llvm_retagx_opaque_writey_readx_disjoint - {tg_x tg_y tg_xparent tr_initial tr_final cids_initial cids_final cid pk opaque range_x range_y} - (AlreadyExists_y : tree_contains tg_y tr_initial) - (Seq : bor_local_seq - {|seq_inv:=fun _ cids => call_is_active cid cids|} - tr_initial cids_initial - ( - [RetagBLEvt tg_xparent tg_x pk cid FnEntry] - ++ opaque - ++ [AccessBLEvt AccessWrite tg_y range_y] - ++ [AccessBLEvt AccessRead tg_x range_x] - ) - tr_final cids_final) - : disjoint' range_y range_x. -Proof. - destruct (proj1 bor_local_seq_split Seq) as [?[?[SeqRetag Seq']]]; clear Seq. - destruct (proj1 bor_local_seq_split Seq') as [?[?[SeqOpaque Seq'']]]; clear Seq'. - destruct (proj1 bor_local_seq_split Seq'') as [?[?[SeqWritey SeqReadx]]]; clear Seq''. - inversion SeqRetag as [|?????? INV1 HEAD1 REST1]. subst. - inversion SeqWritey as [|?????? INV2 HEAD2 REST2]; subst. - inversion SeqReadx as [|?????? INV3 HEAD3 REST3]; subst. - inversion REST1; subst. - inversion HEAD1 as [| | |???????? COMPAT_CID1]. - eapply protected_fwrite_cread_disjoint. - - exact AlreadyExists_y. - - exact HEAD1. - - exists opaque. exact (bor_local_seq_forget SeqOpaque). - - exact INV2. - - exact HEAD2. - - exists []. exact (bor_local_seq_forget REST2). - - exact HEAD3. -Qed. - -Lemma llvm_retagx_opaque_readx_writey_disjoint - {tg_x tg_y tg_xparent tr_initial tr_final cids_initial cids_final cid pk opaque range_x range_y} - (AlreadyExists_y : tree_contains tg_y tr_initial) - (Seq : bor_local_seq - {|seq_inv:=fun _ cids => call_is_active cid cids|} - tr_initial cids_initial - ( - [RetagBLEvt tg_xparent tg_x pk cid FnEntry] - ++ opaque - ++ [AccessBLEvt AccessRead tg_x range_x] - ++ [AccessBLEvt AccessWrite tg_y range_y] - ) - tr_final cids_final) - : disjoint' range_x range_y. -Proof. - destruct (proj1 bor_local_seq_split Seq) as [?[?[SeqRetag Seq']]]; clear Seq. - destruct (proj1 bor_local_seq_split Seq') as [?[?[SeqOpaque Seq'']]]; clear Seq'. - destruct (proj1 bor_local_seq_split Seq'') as [?[?[SeqWritey SeqReadx]]]; clear Seq''. - inversion SeqRetag as [|?????? INV1 HEAD1 REST1]. subst. - inversion SeqReadx as [|?????? INV2 HEAD2 REST2]; subst. - inversion SeqWritey as [|?????? INV3 HEAD3 REST3]; subst. - inversion REST1; subst. - inversion HEAD1 as [| | |???????? COMPAT_CID1]. - eapply protected_cread_fwrite_disjoint. - - exact AlreadyExists_y. - - exact HEAD1. - - exists opaque. exact (bor_local_seq_forget SeqOpaque). - - exact HEAD3. - - exists []. exact REST3. - - exact HEAD2. -Qed. - -Check neven_see_also_the_todo_for_the_local_step_semantics_which_is_missing_a_case. - -Lemma llvm_retagx_opaque_writex_writey_disjoint - {tg_x tg_y tg_xparent tr_initial tr_final cids_initial cids_final cid pk opaque range_x range_y} - (AlreadyExists_y : tree_contains tg_y tr_initial) - (Seq : bor_local_seq - {|seq_inv:=fun _ cids => call_is_active cid cids|} - tr_initial cids_initial - ( - [RetagBLEvt tg_xparent tg_x pk cid FnEntry] - ++ opaque - ++ [AccessBLEvt AccessWrite tg_x range_x] - ++ [AccessBLEvt AccessWrite tg_y range_y] - ) - tr_final cids_final) - : disjoint' range_x range_y. -Proof. - destruct (proj1 bor_local_seq_split Seq) as [?[?[SeqRetag Seq']]]; clear Seq. - destruct (proj1 bor_local_seq_split Seq') as [?[?[SeqOpaque Seq'']]]; clear Seq'. - destruct (proj1 bor_local_seq_split Seq'') as [?[?[SeqWritex SeqWritey]]]; clear Seq''. - inversion SeqRetag as [|?????? INV1 HEAD1 REST1]. subst. - inversion SeqWritey as [|?????? INV3 HEAD2 REST2]; subst. - inversion SeqWritex as [|?????? INV2 HEAD3 REST3]; subst. - inversion REST1; subst. - inversion HEAD1 as [| | |???????? COMPAT_CID1]. - eapply protected_cwrite_fwrite_disjoint. - - exact AlreadyExists_y. - - exact HEAD1. - - exists opaque. exact (bor_local_seq_forget SeqOpaque). - - exact HEAD3. - - exists []. exact REST3. - - exact HEAD2. -Qed. - -Lemma llvm_retagx_opaque_writex_ready_disjoint - {tg_x tg_y tg_xparent tr_initial tr_final cids_initial cids_final cid pk opaque range_x range_y} - (AlreadyExists_y : tree_contains tg_y tr_initial) - (Seq : bor_local_seq - {|seq_inv:=fun _ cids => call_is_active cid cids|} - tr_initial cids_initial - ( - [RetagBLEvt tg_xparent tg_x pk cid FnEntry] - ++ opaque - ++ [AccessBLEvt AccessWrite tg_x range_x] - ++ [AccessBLEvt AccessRead tg_y range_y] - ) - tr_final cids_final) - : disjoint' range_x range_y. -Proof. - destruct (proj1 bor_local_seq_split Seq) as [?[?[SeqRetag Seq']]]; clear Seq. - destruct (proj1 bor_local_seq_split Seq') as [?[?[SeqOpaque Seq'']]]; clear Seq'. - destruct (proj1 bor_local_seq_split Seq'') as [?[?[SeqWritex SeqReady]]]; clear Seq''. - inversion SeqRetag as [|?????? INV1 HEAD1 REST1]. subst. - inversion SeqWritex as [|?????? INV3 HEAD2 REST2]; subst. - inversion SeqReady as [|?????? INV2 HEAD3 REST3]; subst. - inversion REST1; subst. - inversion HEAD1 as [| | |???????? COMPAT_CID1]. - eapply protected_cwrite_fread_disjoint. - - exact AlreadyExists_y. - - exact HEAD1. - - exists opaque. exact (bor_local_seq_forget SeqOpaque). - - exact HEAD2. - - exists []. exact REST2. - - exact HEAD3. -Qed. - -Lemma llvm_retagx_opaque_ready_writex_disjoint - {tg_x tg_y tg_xparent tr_initial tr_final cids_initial cids_final cid pk opaque range_x range_y} - (AlreadyExists_y : tree_contains tg_y tr_initial) - (Seq : bor_local_seq - {|seq_inv:=fun _ cids => call_is_active cid cids|} - tr_initial cids_initial - ( - [RetagBLEvt tg_xparent tg_x pk cid FnEntry] - ++ opaque - ++ [AccessBLEvt AccessRead tg_y range_y] - ++ [AccessBLEvt AccessWrite tg_x range_x] - ) - tr_final cids_final) - : disjoint' range_y range_x. -Proof. - destruct (proj1 bor_local_seq_split Seq) as [?[?[SeqRetag Seq']]]; clear Seq. - destruct (proj1 bor_local_seq_split Seq') as [?[?[SeqOpaque Seq'']]]; clear Seq'. - destruct (proj1 bor_local_seq_split Seq'') as [?[?[SeqReady SeqWritex]]]; clear Seq''. - inversion SeqRetag as [|?????? INV1 HEAD1 REST1]. subst. - inversion SeqReady as [|?????? INV3 HEAD2 REST2]; subst. - inversion SeqWritex as [|?????? INV2 HEAD3 REST3]; subst. - inversion REST1; subst. - inversion HEAD1 as [| | |???????? COMPAT_CID1]. - eapply protected_fread_cwrite_disjoint. - - exact AlreadyExists_y. - - exact HEAD1. - - exists opaque. exact (bor_local_seq_forget SeqOpaque). - - exact INV3. - - exact HEAD2. - - exists []. exact REST2. - - exact HEAD3. -Qed. - - - -(* --- Reordering read-read --- *) - -Definition commutes {X} - (fn1 fn2 : X -> option X) - := forall x0 x1 x2, - fn1 x0 = Some x1 -> - fn2 x1 = Some x2 -> - exists x1', ( - fn2 x0 = Some x1' - /\ fn1 x1' = Some x2 - ). - -Definition commutes_option {X} - (fn1 fn2 : option X -> option X) - := forall x0 x1 x2, - fn1 x0 = Some x1 -> - fn2 (Some x1) = Some x2 -> - exists x1', ( - fn2 x0 = Some x1' - /\ fn1 (Some x1') = Some x2 - ). - -Lemma apply_access_perm_read_commutes - {rel1 rel2 prot} - : commutes - (apply_access_perm AccessRead rel1 prot) - (apply_access_perm AccessRead rel2 prot). -Proof. - move=> p0 p1 p2 Step01 Step12. - unfold apply_access_perm in *. - all: destruct p0 as [[][[][]| | |]]. - all: destruct prot; simpl in *. - all: destruct rel1; simpl in *. - all: try (inversion Step01; done). - all: injection Step01; intros; subst. - all: simpl. - all: destruct rel2; simpl in *. - all: try (inversion Step12; done). - all: injection Step12; intros; subst; simpl. - all: try (eexists; split; [reflexivity|]); simpl. - all: reflexivity. -Qed. - -Lemma mem_apply_loc_insert_ne - {X} {fn : option X -> option X} {z mem mem' z0} - (NE : ~z = z0) - (Success : mem_apply_loc fn z mem = Some mem') - v0 - : mem_apply_loc fn z (<[z0:=v0]>mem) = Some (<[z0:=v0]>mem'). -Proof. - unfold mem_apply_loc in Success |- *; simpl in *. - rewrite lookup_insert_ne; [|auto]. - destruct (option_bind_success_step _ _ _ Success) as [v [fnv mem'_spec]]. - injection mem'_spec; intros; subst. - rewrite fnv; simpl. - f_equal. - rewrite insert_commute; auto. -Qed. - -Lemma mem_apply_range'_insert_outside - {X} {fn : option X -> option X} {z sz mem mem' z0} - (OUT : ~range'_contains (z, sz) z0) - (Success : mem_apply_locs fn z sz mem = Some mem') - v0 - : mem_apply_locs fn z sz (<[z0:=v0]>mem) = Some (<[z0:=v0]>mem'). -Proof. - unfold mem_apply_range' in *; simpl in *. - generalize dependent z. - generalize dependent mem. - generalize dependent mem'. - induction sz as [|sz IHsz]; move=> mem' mem z OUT Success. - - injection Success; intros; subst. - reflexivity. - - destruct (proj1 (bind_Some _ _ _) Success) as [mem'' [SuccessStep SuccessRest]]. - simpl. - erewrite mem_apply_loc_insert_ne; [| |eassumption]. - 2: { unfold range'_contains in OUT |- *; simpl in *; lia. } - simpl. - apply IHsz. - + unfold range'_contains in OUT |- *; simpl in *; lia. - + exact SuccessRest. -Qed. - -Lemma mem_apply_range'_success_condition - {X} {fn : option X -> option X} {range mem} - (ALL_SOME : forall z, range'_contains range z -> is_Some (fn (mem !! z))) - : exists mem', mem_apply_range' fn range mem = Some mem'. -Proof. - unfold mem_apply_range'. - destruct range as [z sz]; simpl. - generalize dependent z. - induction sz as [|sz IHsz]; move=> z ALL_SOME. - - eexists. simpl. reflexivity. - - destruct (IHsz (z + 1)%Z - ltac:(intros mem' H; apply ALL_SOME; unfold range'_contains; unfold range'_contains in H; simpl; simpl in H; lia)) - as [sub' Specsub']. - destruct (ALL_SOME z ltac:(unfold range'_contains; simpl; lia)) as [fnz Specfnz]. - eexists (<[z:=fnz]>sub'); simpl. - unfold mem_apply_loc. - rewrite Specfnz; simpl. - erewrite mem_apply_range'_insert_outside; [reflexivity| |assumption]. - unfold range'_contains; simpl; lia. -Qed. - -Lemma mem_apply_range'_success_specification - {X} {fn : option X -> option X} {range mem mem'} - (ALL_SOME : forall z, range'_contains range z -> exists x', fn (mem !! z) = Some x' /\ mem' !! z = Some x') - (REST_SAME : forall z, ~range'_contains range z -> mem !! z = mem' !! z) - : mem_apply_range' fn range mem = Some mem'. -Proof. - assert (forall z, range'_contains range z -> is_Some (fn (mem !! z))) as ALL_SOME_weaker. { - intros z R; destruct (ALL_SOME z R) as [?[??]]; auto. - } - destruct (mem_apply_range'_success_condition ALL_SOME_weaker) as [mem'' Spec'']. - rewrite Spec''; f_equal; apply map_eq. - intro z. - pose proof (mem_apply_range'_spec _ _ z _ _ Spec'') as Spec. - destruct (decide (range'_contains range z)) as [R|nR]. - - destruct Spec as [v[vSpec fnvSpec]]. - destruct (ALL_SOME z R) as [v' [fnv'Spec v'Spec]]. - rewrite v'Spec. - rewrite vSpec. - rewrite <- fnv'Spec. - rewrite <- fnvSpec. - reflexivity. - - rewrite <- (REST_SAME z nR). - assumption. -Qed. - -Lemma range_foreach_commutes - {X} - range1 range2 - (fn1 fn2 : option X -> option X) - (FnCommutes : commutes_option fn1 fn2) - : commutes - (mem_apply_range' fn1 range1) - (mem_apply_range' fn2 range2). -Proof. - intros mem0 mem1 mem2 Success01 Success12. - assert (forall z, range'_contains range2 z -> exists x1', fn2 (mem0 !! z) = Some x1') as fn2mem0. { - intros z R2. - pose proof (mem_apply_range'_spec _ _ z _ _ Success01) as Spec01. - pose proof (mem_apply_range'_spec _ _ z _ _ Success12) as Spec12. - destruct (decide (range'_contains range1 z)). - - destruct Spec01 as [fn1z0 [z1Spec fn1z0Spec]]. - rewrite decide_True in Spec12; [|assumption]. - destruct Spec12 as [fn2z1 [z2Spec fn2z1Spec]]. - rewrite z1Spec in fn2z1Spec. - destruct (FnCommutes _ _ _ fn1z0Spec fn2z1Spec) as [x1' [fn2z0Spec fn1x1'Spec]]. - exists x1'; assumption. - - rewrite decide_True in Spec12; [|assumption]. - destruct Spec12 as [x2 [x2Spec fn2x1Spec]]. - exists x2; rewrite <- Spec01; assumption. - } - destruct (mem_apply_range'_success_condition fn2mem0) as [mem1' Success01']. - exists mem1'. - split; [assumption|]. - apply mem_apply_range'_success_specification. - - intros z R1. - pose proof (mem_apply_range'_spec _ _ z _ _ Success01) as Spec01. - pose proof (mem_apply_range'_spec _ _ z _ _ Success12) as Spec12. - pose proof (mem_apply_range'_spec _ _ z _ _ Success01') as Spec01'. - destruct (decide (range'_contains range2 z)). - + rewrite decide_True in Spec01; [|assumption]. - destruct Spec01 as [fn1z0 [z1Spec fn1z0Spec]]. - destruct Spec12 as [fn2z1 [z2Spec fn2z1Spec]]. - destruct Spec01' as [fn2z0 [z1'Spec fn2z0Spec]]. - rewrite z1Spec in fn2z1Spec. - destruct (FnCommutes _ _ _ fn1z0Spec fn2z1Spec) as [x2' [fn2z0'Spec fn1x2'Spec]]. - rewrite z1'Spec. - rewrite <- fn2z0Spec. - exists fn2z1. - split; [|assumption]. - destruct (FnCommutes _ _ _ fn1z0Spec fn2z1Spec) as [x1' [fn2z0Spec' fn1x1'Spec]]. - rewrite fn2z0Spec'. - rewrite fn1x1'Spec. - reflexivity. - + rewrite decide_True in Spec01; [|assumption]. - destruct Spec01 as [fn1z0 [z1Spec fn1z0Spec]]. - rewrite Spec01'. - rewrite Spec12. - exists fn1z0; split; assumption. - - intros z nR1. - pose proof (mem_apply_range'_spec _ _ z _ _ Success01) as Spec01. - pose proof (mem_apply_range'_spec _ _ z _ _ Success01') as Spec01'. - pose proof (mem_apply_range'_spec _ _ z _ _ Success12) as Spec12. - destruct (decide (range'_contains range2 z)). - + rewrite decide_False in Spec01; [|assumption]. - destruct Spec01' as [fn2z0 [z1'Spec fn2z0Spec]]. - destruct Spec12 as [fn2z1 [z2Spec fn2z1Spec]]. - rewrite z1'Spec. - rewrite <- fn2z0Spec. - rewrite <- Spec01. - rewrite fn2z1Spec. - rewrite z2Spec. - reflexivity. - + rewrite decide_False in Spec01; [|assumption]. - rewrite Spec01'. - rewrite <- Spec01. - rewrite Spec12. - reflexivity. -Qed. - -Lemma range_foreach_disjoint_commutes - {X} {fn1 fn2 : option X -> option X} {range1 range2} - (Disjoint : disjoint' range1 range2) - : commutes - (mem_apply_range' fn1 range1) - (mem_apply_range' fn2 range2). -Proof. - intros mem0 mem1 mem2 Success01 Success12. - assert (forall z, range'_contains range2 z -> exists x1', fn2 (mem0 !! z) = Some x1') as fn2mem0. { - intros z R2. - pose proof (mem_apply_range'_spec _ _ z _ _ Success01) as Spec01. - pose proof (mem_apply_range'_spec _ _ z _ _ Success12) as Spec12. - destruct (decide (range'_contains range1 z)). - - exfalso; apply Disjoint; eexists; eauto. - - rewrite decide_True in Spec12; [|assumption]. - destruct Spec12 as [x2 [x2Spec fn2x1Spec]]. - exists x2; rewrite <- Spec01; assumption. - } - destruct (mem_apply_range'_success_condition fn2mem0) as [mem1' Success01']. - exists mem1'. - split; [assumption|]. - apply mem_apply_range'_success_specification. - - intros z R1. - pose proof (mem_apply_range'_spec _ _ z _ _ Success01) as Spec01. - pose proof (mem_apply_range'_spec _ _ z _ _ Success12) as Spec12. - pose proof (mem_apply_range'_spec _ _ z _ _ Success01') as Spec01'. - destruct (decide (range'_contains range2 z)). - + exfalso; apply Disjoint; eexists; eauto. - + rewrite decide_True in Spec01; [|assumption]. - destruct Spec01 as [fn1z0 [z1Spec fn1z0Spec]]. - rewrite Spec01'. - rewrite Spec12. - exists fn1z0; split; assumption. - - intros z nR1. - pose proof (mem_apply_range'_spec _ _ z _ _ Success01) as Spec01. - pose proof (mem_apply_range'_spec _ _ z _ _ Success01') as Spec01'. - pose proof (mem_apply_range'_spec _ _ z _ _ Success12) as Spec12. - destruct (decide (range'_contains range2 z)). - + rewrite decide_False in Spec01; [|assumption]. - destruct Spec01' as [fn2z0 [z1'Spec fn2z0Spec]]. - destruct Spec12 as [fn2z1 [z2Spec fn2z1Spec]]. - rewrite z1'Spec. - rewrite <- fn2z0Spec. - rewrite <- Spec01. - rewrite fn2z1Spec. - rewrite z2Spec. - reflexivity. - + rewrite decide_False in Spec01; [|assumption]. - rewrite Spec01'. - rewrite <- Spec01. - rewrite Spec12. - reflexivity. -Qed. - -Lemma commutes_option_build - {X} {dflt : X} {fn1 fn2} - (Commutes : commutes fn1 fn2) - : commutes_option - (fun ox => fn1 (default dflt ox)) - (fun ox => fn2 (default dflt ox)). -Proof. - intros x0 x1 x2 Step01 Step12. - destruct (Commutes (default dflt x0) _ _ Step01 Step12) as [?[??]]. - eexists; eauto. -Qed. - -Lemma permissions_foreach_commutes - range1 range2 - (fn1 fn2 : lazy_permission -> option lazy_permission) - dflt - (FnCommutes : commutes fn1 fn2) - : commutes - (permissions_apply_range' dflt range1 fn1) - (permissions_apply_range' dflt range2 fn2). -Proof. - apply range_foreach_commutes. - apply commutes_option_build. - assumption. -Qed. - -Lemma permissions_foreach_disjoint_commutes - range1 range2 - (fn1 fn2 : lazy_permission -> option lazy_permission) - dflt - (Disjoint : disjoint' range1 range2) - : commutes - (permissions_apply_range' dflt range1 fn1) - (permissions_apply_range' dflt range2 fn2). -Proof. - apply range_foreach_disjoint_commutes. - assumption. -Qed. - -Lemma item_apply_access_read_commutes - {cids rel1 rel2 range1 fn1 fn2 range2} - (FnCommutes : forall isprot, - commutes - (fn1 rel1 isprot) - (fn2 rel2 isprot)) - : commutes - (item_apply_access fn1 cids rel1 range1) - (item_apply_access fn2 cids rel2 range2). -Proof. - intros it0 it1 it2 Step01 Step12. - option step in Step01 as ?:S1. - option step in Step12 as ?:S2. - injection Step01; destruct it1 as [??? iperm1]; intro H; injection H; intros; subst; simpl in *; clear Step01; clear H. - injection Step12; destruct it2 as [??? iperm2]; intro H; injection H; intros; subst; simpl in *; clear Step12; clear H. - destruct (permissions_foreach_commutes - range1 range2 - (fn1 _ _) (fn2 _ _) - {| initialized:=PermLazy; perm:=initp it0 |} - (FnCommutes _) - (*(apply_access_perm_read_commutes (rel1:=rel1) (rel2:=rel2) (prot:=bool_decide (protector_is_active (iprot it0) cids)))*) - (iperm it0) iperm1 iperm2 - S1 S2) as [perms' [Pre Post]]. - unfold item_apply_access. - rewrite Pre; simpl. - eexists; split; [reflexivity|]. - simpl. rewrite Post; simpl. - reflexivity. -Qed. - -Lemma item_apply_access_disjoint_commutes - {cids rel1 rel2 fn1 fn2 range1 range2} - (Disjoint : disjoint' range1 range2) - : commutes - (item_apply_access fn1 cids rel1 range1) - (item_apply_access fn2 cids rel2 range2). -Proof. - intros it0 it1 it2 Step01 Step12. - option step in Step01 as ?:S1. - option step in Step12 as ?:S2. - injection Step01; destruct it1; intro H; injection H; intros; subst; simpl in *; clear Step01; clear H. - injection Step12; destruct it2; intro H; injection H; intros; subst; simpl in *; clear Step12; clear H. - edestruct (permissions_foreach_disjoint_commutes - range1 range2 - (fn1 rel1 (bool_decide (protector_is_active (iprot it0) cids))) - (fn2 rel2 (bool_decide (protector_is_active (iprot it0) cids))) - {| initialized:=PermLazy; perm:=initp it0 |} - ) as [?[Pre Post]]; eauto. - unfold item_apply_access. - rewrite Pre; simpl. - eexists; split; [reflexivity|]. - simpl. rewrite Post; simpl. - reflexivity. -Qed. - -Lemma apply_access_success_condition - {fn cids access_tag range tr} - (ALL_SOME : every_node - (fun it => is_Some (item_apply_access fn cids (rel_dec tr access_tag (itag it)) range it)) tr) - : exists tr', tree_apply_access fn cids access_tag range tr = Some tr'. -Proof. - assert (every_node is_Some (map_nodes (fun it => item_apply_access fn cids (rel_dec tr access_tag (itag it)) range it) tr)) as AllSomeMap by (rewrite every_node_map; assumption). - destruct (proj2 (join_success_condition _) AllSomeMap). - eexists; eassumption. -Qed. - -Lemma join_map_commutes - {fn1 fn2 : call_id_set -> rel_pos -> Z * nat -> item -> option item} {cids access_tag1 access_tag2 range1 range2} - (Fn1PreservesTag : forall it it' cids rel range, fn1 cids rel range it = Some it' -> itag it = itag it') - (Fn2PreservesTag : forall it it' cids rel range, fn2 cids rel range it = Some it' -> itag it = itag it') - (Commutes : forall rel1 rel2, commutes - (fn1 cids rel1 range1) - (fn2 cids rel2 range2)) - (* We need the two [rel_dec] to refer to the same tree otherwise the proof would be much more difficult *) - : forall (tr0:tree item), - commutes - (fun tr => join_nodes (map_nodes (fun it => fn1 cids (rel_dec tr0 access_tag1 it.(itag)) range1 it) tr)) - (fun tr => join_nodes (map_nodes (fun it => fn2 cids (rel_dec tr0 access_tag2 it.(itag)) range2 it) tr)). -Proof. - intros tr tr0. - induction tr0 as [|data0 left0 IHleft right0 IHright]; intros tr1 tr2 Step01 Step12. - - simpl in Step01; injection Step01; intros; subst. - simpl in Step12; injection Step12; intros; subst. - exists tree.empty; simpl; tauto. - - option step in Step01 as data1:Data01. - option step in Step01 as left1:Left01. - option step in Step01 as right1:Right01. - injection Step01; intros; subst. - option step in Step12 as data2:Data12. - option step in Step12 as left2:Left12. - option step in Step12 as right2:Right12. - injection Step12; intros; subst. - destruct (Commutes _ _ data0 data1 data2 Data01 Data12) as [data1' [Data01' Data1'2]]. - destruct (IHleft left1 left2 Left01 Left12) as [left1' [Left01' Left1'2]]. - destruct (IHright right1 right2 Right01 Right12) as [right1' [Right01' Right1'2]]. - exists (branch data1' left1' right1'). - simpl in *. - assert (itag data0 = itag data1) as Tg01 by (eapply Fn1PreservesTag; eassumption). - assert (itag data0 = itag data1') as Tg01' by (eapply Fn2PreservesTag; eassumption). - rewrite Tg01; rewrite Data01'; simpl. - rewrite Left01'; simpl. - rewrite Right01'; simpl. - rewrite <- Tg01'; rewrite Data1'2; simpl. - rewrite Left1'2; simpl. - rewrite Right1'2; simpl. - tauto. -Qed. - -Lemma tree_apply_access_only_cares_about_rel - {tr} {fn : call_id_set -> rel_pos -> Z * nat -> item -> option item} {cids access_tag range} - {tr1 tr2} - (Agree : forall tg tg', ParentChildIn tg tg' tr1 <-> ParentChildIn tg tg' tr2) - (RAgree : forall tg tg', ImmediateParentChildIn tg tg' tr1 <-> ImmediateParentChildIn tg tg' tr2) - : join_nodes (map_nodes (fun it => fn cids (rel_dec tr1 access_tag it.(itag)) range it) tr) - = join_nodes (map_nodes (fun it => fn cids (rel_dec tr2 access_tag it.(itag)) range it) tr). -Proof. - induction tr as [|data sibling IHsibling child IHchild]; [simpl; reflexivity|]. - simpl. - rewrite IHsibling; clear IHsibling. - rewrite IHchild; clear IHchild. - unfold rel_dec. - f_equal. f_equal. - destruct (decide (ParentChildIn _ _ _)) as [R1|R1]. - all: destruct (decide (ParentChildIn _ _ _)) as [R1'|R1']. - all: destruct (decide (ParentChildIn _ _ _)) as [R2|R2]. - all: destruct (decide (ParentChildIn _ _ _)) as [R2'|R2']. - all: try reflexivity. - all: rewrite <- Agree in R2'; auto; try contradiction. - all: rewrite <- Agree in R2; auto; try contradiction. - all: erewrite decide_ext; last apply RAgree. - all: done. -Qed. - -Lemma tree_apply_access_commutes - {fn1 fn2 cids access_tag1 access_tag2 range1 range2} - (Commutes : forall rel1 rel2, commutes - (item_apply_access fn1 cids rel1 range1) - (item_apply_access fn2 cids rel2 range2)) - : commutes - (fun tr => tree_apply_access fn1 cids access_tag1 range1 tr) - (fun tr => tree_apply_access fn2 cids access_tag2 range2 tr). -Proof. - unfold tree_apply_access. - intros tr0 tr1 tr2 Step01 Step12. - assert (forall (it it' : item) (cids : call_id_set) (rel : rel_pos) (range : Z * nat), - item_apply_access fn1 cids rel range it = Some it' - → itag it = itag it') as Fn1PreservesTag. { - intros. eapply item_apply_access_preserves_metadata. eassumption. - } - assert (forall (it it' : item) (cids : call_id_set) (rel : rel_pos) (range : Z * nat), - item_apply_access fn2 cids rel range it = Some it' - → itag it = itag it') as Fn2PreservesTag. { - intros. eapply item_apply_access_preserves_metadata. eassumption. - } - - erewrite tree_apply_access_only_cares_about_rel in Step01. - 1: erewrite tree_apply_access_only_cares_about_rel in Step12. - 1: edestruct (join_map_commutes - Fn1PreservesTag - Fn2PreservesTag - Commutes _ tr0 tr1 tr2 Step01 Step12) as [tr1' [Step01' Step1'2]]. 1: exists tr1'; split; [exact Step01'|]. - 1: erewrite tree_apply_access_only_cares_about_rel in Step1'2. - 1: exact Step1'2. - all: intros tg tg'. - - eapply join_map_eqv_rel; [|eassumption]. intros it it' H. eapply Fn2PreservesTag. exact H. - - eapply join_map_eqv_imm_rel; [|eassumption]. intros it it' H. eapply Fn2PreservesTag. exact H. - - symmetry. eapply join_map_eqv_rel; [|eassumption]. intros it it' H. eapply Fn1PreservesTag. exact H. - - symmetry. eapply join_map_eqv_imm_rel; [|eassumption]. intros it it' H. eapply Fn1PreservesTag. exact H. - - tauto. - - tauto. -Qed. - -Lemma memory_access_read_commutes - {cids access_tag1 access_tag2 range1 range2} - : commutes - (memory_access AccessRead cids access_tag1 range1) - (memory_access AccessRead cids access_tag2 range2). -Proof. - unfold memory_access. - apply tree_apply_access_commutes; intros. - apply item_apply_access_read_commutes; intros. - apply apply_access_perm_read_commutes. -Qed. - -Lemma memory_access_disjoint_commutes - {cids kind1 kind2 access_tag1 access_tag2 range1 range2} - (Disjoint : disjoint' range1 range2) - : commutes - (memory_access kind1 cids access_tag1 range1) - (memory_access kind2 cids access_tag2 range2). -Proof. - unfold memory_access. - apply tree_apply_access_commutes; intros. - apply item_apply_access_disjoint_commutes; intros. - assumption. -Qed. - -Lemma llvm_read_read_reorder - {tr_initial cids_initial tr_final cids_final access_tag1 access_tag2 range1 range2} - (Seq12 : bor_local_seq - {|seq_inv:=fun _ _ => True|} - tr_initial cids_initial - ( - [AccessBLEvt AccessRead access_tag1 range1] - ++ [AccessBLEvt AccessRead access_tag2 range2] - ) - tr_final cids_final - ) - : bor_local_seq - {|seq_inv:=fun _ _ => True|} - tr_initial cids_initial - ( - [AccessBLEvt AccessRead access_tag2 range2] - ++ [AccessBLEvt AccessRead access_tag1 range1] - ) - tr_final cids_final. -Proof. - rewrite bor_local_seq_split. - rewrite bor_local_seq_split in Seq12. - destruct Seq12 as [tr_interm [cids_interm [Pre Post]]]. - inversion Pre as [|??????? HEAD1 REST1]; subst. - inversion Post as [|??????? HEAD2 REST2]; subst. - inversion REST1 as [INV1|]; subst. - inversion REST2 as [INV2|]; subst. - inversion HEAD1 as [????? ACC1| | |]; subst. - inversion HEAD2 as [????? ACC2| | |]; subst. - destruct (memory_access_read_commutes tr_initial tr_interm tr_final ACC1 ACC2) as [tr_alt [PreAlt PostAlt]]. - exists tr_alt, cids_final. - split. - - econstructor; [done|constructor; [|exact PreAlt]|constructor; done]. - erewrite access_preserves_tags; eauto; apply item_apply_access_preserves_metadata. - - econstructor; [done|constructor; [|exact PostAlt]|constructor; done]. - erewrite <- access_preserves_tags; eauto; apply item_apply_access_preserves_metadata. -Qed. - -Lemma disjoint'_sym {range1 range2} : disjoint' range1 range2 <-> disjoint' range2 range1. -Proof. unfold disjoint'; split; intros P Q; apply P; destruct Q as [?[??]]; eexists; split; eauto. Qed. - -Lemma llvm_disjoint_reorder - {tr_initial cids_initial tr_final cids_final access_tag1 access_tag2 range1 range2 kind1 kind2} - (Disjoint : disjoint' range1 range2) - (Seq12 : bor_local_seq - {|seq_inv:=fun _ _ => True|} - tr_initial cids_initial - ( - [AccessBLEvt kind1 access_tag1 range1] - ++ [AccessBLEvt kind2 access_tag2 range2] - ) - tr_final cids_final - ) - : bor_local_seq - {|seq_inv:=fun _ _ => True|} - tr_initial cids_initial - ( - [AccessBLEvt kind2 access_tag2 range2] - ++ [AccessBLEvt kind1 access_tag1 range1] - ) - tr_final cids_final. -Proof. - rewrite bor_local_seq_split. - rewrite bor_local_seq_split in Seq12. - destruct Seq12 as [tr_interm [cids_interm [Pre Post]]]. - inversion Pre as [|??????? HEAD1 REST1]; subst. - inversion Post as [|??????? HEAD2 REST2]; subst. - inversion REST1 as [INV1|]; subst. - inversion REST2 as [INV2|]; subst. - inversion HEAD1 as [????? ACC1| | |]; subst. - inversion HEAD2 as [????? ACC2| | |]; subst. - destruct (memory_access_disjoint_commutes Disjoint tr_initial tr_interm tr_final ACC1 ACC2) as [tr_alt [PreAlt PostAlt]]. - - exists tr_alt, cids_final. - split. - - econstructor; [done|constructor; [|exact PreAlt]|constructor; done]. - erewrite access_preserves_tags; eauto; apply item_apply_access_preserves_metadata. - - econstructor; [done|constructor; [|exact PostAlt]|constructor; done]. - erewrite <- access_preserves_tags; eauto; apply item_apply_access_preserves_metadata. -Qed. - -Lemma bor_local_seq_accesses_same_cids - {tr cid cids evts tr' cids'} - (StartsActive : call_is_active cid cids) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - (NoEndCall : Forall (fun evt => evt ≠EndCallBLEvt cid) evts) - : bor_local_seq - {|seq_inv:=fun _ cids => call_is_active cid cids|} - tr cids evts tr' cids'. -Proof. - generalize dependent tr. - generalize dependent cids. - induction evts as [|?? IHevts]; move=> ??? Seq; inversion Seq as [|??????? HEAD]; subst. - - constructor; assumption. - - econstructor. - + assumption. - + eassumption. - + eapply IHevts. - * inversion NoEndCall; subst; assumption. - * inversion HEAD as [| |cid0|]; subst. - -- eassumption. - -- unfold call_is_active. rewrite elem_of_union. right. - assumption. - -- assert (cid ≠cid0) as OtherCid by (intro; inversion NoEndCall as [|?? NE]; apply NE; subst; reflexivity). - unfold call_is_active. rewrite elem_of_difference. - split; [assumption|]. - rewrite not_elem_of_singleton; assumption. - -- assumption. - * assumption. -Qed. - -Theorem llvm_noalias_reorder - {tg_xparent pk cid} - {tg_x kind_x range_x} - {tg_y kind_y range_y} - {tr_initial cids_initial opaque tr_final cids_final} - (AlreadyExists_y : tree_contains tg_y tr_initial) : - let retag_x := RetagBLEvt tg_xparent tg_x pk cid FnEntry in - let access_y := AccessBLEvt kind_y tg_y range_y in - let access_x := AccessBLEvt kind_x tg_x range_x in - let invariant := {| seq_inv := fun _ cids => call_is_active cid cids |} in - (bor_local_seq invariant tr_initial cids_initial ([retag_x] ++ opaque ++ [access_y] ++ [access_x]) tr_final cids_final) - <-> - (bor_local_seq invariant tr_initial cids_initial ([retag_x] ++ opaque ++ [access_x] ++ [access_y]) tr_final cids_final). -Proof. - split; intro Seq. - - destruct kind_x, kind_y. - 2: assert (disjoint' range_y range_x) by (eapply llvm_retagx_opaque_writey_readx_disjoint; eassumption). - 3: assert (disjoint' range_y range_x) by (eapply llvm_retagx_opaque_ready_writex_disjoint; eassumption). - 4: assert (disjoint' range_y range_x) by (eapply llvm_retagx_opaque_writey_writex_disjoint; eassumption). - all: rewrite bor_local_seq_split in Seq; destruct Seq as [?[? [Pre1 Seq]]]. - all: rewrite bor_local_seq_split in Seq; destruct Seq as [?[? [Pre2 Seq]]]. - all: rewrite bor_local_seq_split; eexists; eexists; split; [eassumption|]. - all: rewrite bor_local_seq_split; eexists; eexists; split; [eassumption|]. - all: eapply bor_local_seq_accesses_same_cids; [exact (seq_always_destruct_first Seq)| |simpl; auto]. - 1: apply llvm_read_read_reorder; eapply bor_local_seq_forget; eassumption. - all: apply llvm_disjoint_reorder; [assumption|]. - all: eapply bor_local_seq_forget; eassumption. - - destruct kind_x, kind_y. - 2: assert (disjoint' range_x range_y) by (eapply llvm_retagx_opaque_readx_writey_disjoint; eassumption). - 3: assert (disjoint' range_x range_y) by (eapply llvm_retagx_opaque_writex_ready_disjoint; eassumption). - 4: assert (disjoint' range_x range_y) by (eapply llvm_retagx_opaque_writex_writey_disjoint; eassumption). - all: rewrite bor_local_seq_split in Seq; destruct Seq as [?[? [Pre1 Seq]]]. - all: rewrite bor_local_seq_split in Seq; destruct Seq as [?[? [Pre2 Seq]]]. - all: rewrite bor_local_seq_split; eexists; eexists; split; [eassumption|]. - all: rewrite bor_local_seq_split; eexists; eexists; split; [eassumption|]. - all: eapply bor_local_seq_accesses_same_cids; [exact (seq_always_destruct_first Seq)| |simpl; auto]. - 1: apply llvm_read_read_reorder; eapply bor_local_seq_forget; eassumption. - all: apply llvm_disjoint_reorder; [assumption|]. - all: eapply bor_local_seq_forget; eassumption. -Qed. - -Check neven_see_also_the_todo_for_the_local_step_semantics_which_is_missing_a_case. -*) diff --git a/theories/tree_borrows/early_proofmode.v b/theories/tree_borrows/early_proofmode.v index ac921fdaef4c191c6a4230a9ed01fef989219f35..d97906d38bd76ae1322b0102aacb3dde182d1fa2 100644 --- a/theories/tree_borrows/early_proofmode.v +++ b/theories/tree_borrows/early_proofmode.v @@ -378,7 +378,6 @@ Ltac sim_val := sim_finish; sim_result_head. (** ** Pure reduction *) Ltac solve_pure_sidecond := - (*TODO: have tactic adapted to our instances *) fast_done || (left; fast_done) || (right; fast_done). (** The argument [efoc] can be used to specify the construct that should be diff --git a/theories/tree_borrows/examples/protected/mutable_reorder_read_down.v b/theories/tree_borrows/examples/protected/mutable_reorder_read_down.v index 2c49abb349e078eba831d71c4d35adf5aed0a5e7..73d7c59688c60d32d20c389f02f67b402503b68c 100755 --- a/theories/tree_borrows/examples/protected/mutable_reorder_read_down.v +++ b/theories/tree_borrows/examples/protected/mutable_reorder_read_down.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From simuliris.simulation Require Import lifting. From simuliris.tree_borrows Require Import primitive_laws proofmode examples.lib adequacy. From iris.prelude Require Import options. @@ -127,8 +123,10 @@ Section closed. Qed. End closed. +(* Check prot_mutable_reorder_read_down_ctx. Print Assumptions prot_mutable_reorder_read_down_ctx. +*) (* prot_mutable_reorder_read_down_ctx : ctx_ref prot_mutable_reorder_read_down_opt prot_mutable_reorder_read_down_unopt diff --git a/theories/tree_borrows/examples/protected/mutable_reorder_read_up.v b/theories/tree_borrows/examples/protected/mutable_reorder_read_up.v index 39171b47828256ea4a1109befe0d43dd587da936..a31f72c9df7827cd121910b493307e39bcb353f4 100755 --- a/theories/tree_borrows/examples/protected/mutable_reorder_read_up.v +++ b/theories/tree_borrows/examples/protected/mutable_reorder_read_up.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From simuliris.simulation Require Import lifting. From simuliris.tree_borrows Require Import primitive_laws proofmode examples.lib adequacy. From iris.prelude Require Import options. @@ -128,8 +124,10 @@ Section closed. Qed. End closed. +(* Check prot_mutable_reorder_read_up_ctx. Print Assumptions prot_mutable_reorder_read_up_ctx. +*) (* prot_mutable_reorder_read_up_ctx : ctx_ref prot_mutable_reorder_read_up_opt prot_mutable_reorder_read_up_unopt diff --git a/theories/tree_borrows/examples/protected/mutable_reorder_write_down_activated.v b/theories/tree_borrows/examples/protected/mutable_reorder_write_down_activated.v index ae4933d020195ab3cdcf8b3b7736a7e87bf43f0e..41fd8d98f8f69ce21df03eb4580b5110c5d8d2af 100755 --- a/theories/tree_borrows/examples/protected/mutable_reorder_write_down_activated.v +++ b/theories/tree_borrows/examples/protected/mutable_reorder_write_down_activated.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From simuliris.simulation Require Import lifting. From simuliris.tree_borrows Require Import proofmode lang adequacy examples.lib. From iris.prelude Require Import options. @@ -178,8 +174,10 @@ Section closed. Qed. End closed. +(* Check prot_mutable_reorder_write_down_activated_ctx. Print Assumptions prot_mutable_reorder_write_down_activated_ctx. +*) (* prot_mutable_reorder_write_down_activated_ctx : ctx_ref prot_mutable_reorder_write_down_activated_opt prot_mutable_reorder_write_down_activated_unopt diff --git a/theories/tree_borrows/examples/protected/mutable_reorder_write_up_activated.v b/theories/tree_borrows/examples/protected/mutable_reorder_write_up_activated.v index a12caee72f3fa603437e194c583f7177dd7a106f..9c3532c516b738bc99b2fa3b350b69c6ec5de26f 100755 --- a/theories/tree_borrows/examples/protected/mutable_reorder_write_up_activated.v +++ b/theories/tree_borrows/examples/protected/mutable_reorder_write_up_activated.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From simuliris.simulation Require Import lifting. From simuliris.tree_borrows Require Import proofmode lang adequacy examples.lib. From iris.prelude Require Import options. @@ -136,8 +132,10 @@ Section closed. Qed. End closed. +(* Check prot_mutable_reorder_write_up_activated_ctx. Print Assumptions prot_mutable_reorder_write_up_activated_ctx. +*) (* prot_mutable_reorder_write_up_activated_ctx : ctx_ref prot_mutable_reorder_write_up_activated_opt prot_mutable_reorder_write_up_activated_unopt diff --git a/theories/tree_borrows/examples/protected/mutable_reorder_write_up_activated_paper.v b/theories/tree_borrows/examples/protected/mutable_reorder_write_up_activated_paper.v new file mode 100644 index 0000000000000000000000000000000000000000..3a5ee20d6b10baf028a78dd5fae284796ee605ef --- /dev/null +++ b/theories/tree_borrows/examples/protected/mutable_reorder_write_up_activated_paper.v @@ -0,0 +1,159 @@ +From simuliris.simulation Require Import lifting. +From simuliris.tree_borrows Require Import proofmode lang adequacy examples.lib. +From iris.prelude Require Import options. + + +(** Moving a write to a mutable reference up across unknown code. *) + +(* Assuming x : &mut i32 *) +Definition prot_mutable_reorder_write_up_activated_paper_unopt : expr := + let: "c" := InitCall in + (* "x" is the local variable that stores the pointer value "i" *) + let: "x" := new_place sizeof_scalar "i" in + + (* retag_place reborrows the pointer value stored in "x" (which is "i"), + then updates "x" with the new pointer value. This relies on protectors, + hence [FnEntry]. *) + retag_place "x" MutRef TyFrz sizeof_scalar FnEntry "c";; + + (* Call the unknown function "f" *) + Call #[ScFnPtr "f"] "f_closure_arg" ;; + + (* Write 10 to the cell pointed to by the pointer in "x" *) + *{sizeof_scalar} "x" <- #[10] ;; + + (* Call the unknown function "g" *) + Call #[ScFnPtr "g"] "g_closure_arg" ;; + + (* Write 0 to the cell pointed to by the pointer in "x" *) + *{sizeof_scalar} "x" <- #[0] ;; + + (* Free the local variable *) + Free "x" ;; + + (* Finally, return unit *) + EndCall "c";; + #[] + . + +Definition prot_mutable_reorder_write_up_activated_paper_opt : expr := + let: "c" := InitCall in + let: "x" := new_place sizeof_scalar "i" in + retag_place "x" MutRef TyFrz sizeof_scalar FnEntry "c";; + Call #[ScFnPtr "f"] "f_closure_arg" ;; + *{sizeof_scalar} "x" <- #[0] ;; + Call #[ScFnPtr "g"] "g_closure_arg" ;; + Free "x" ;; + EndCall "c";; + #[] + . + +Lemma prot_mutable_reorder_write_up_activated_paper `{sborGS Σ} : + ⊢ log_rel prot_mutable_reorder_write_up_activated_paper_opt prot_mutable_reorder_write_up_activated_paper_unopt. +Proof. + log_rel. + iIntros "%f_closure_t %f_closure_s #Hrel_f_closure". + iIntros "%r_t %r_s #Hrel". + iIntros "%g_closure_t %g_closure_s #Hrel_g_closure". + iIntros "!# %Ï€ _". + sim_pures. + rewrite !subst_result. + sim_apply InitCall InitCall sim_init_call "". iIntros (c) "Hcall". iApply sim_expr_base. sim_pures. + + (* new place *) + simpl. source_bind (new_place _ _). + iApply source_red_safe_reach. + { intros. rewrite subst_result. eapply new_place_safe_reach. } + simpl. iIntros "(%v_s & -> & %Hsize)". destruct v_s as [|v_s [|?]]; try done. + iPoseProof (rrel_value_source with "Hrel") as (v_t) "(-> & #Hv)". + iPoseProof (value_rel_length with "Hv") as "%Hlen". destruct v_t as [|v_t [|?]]; try done. + iApply source_red_base. iModIntro. to_sim. + sim_apply (new_place _ _) (new_place _ _) sim_new_place_local "%t %l % % Htag Ht Hs"; first done. + sim_pures. + + target_apply (Copy _) (target_copy_local with "Htag Ht") "Ht Htag". 2: done. 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. + source_apply (Copy _) (source_copy_local with "Htag Hs") "Hs Htag". 2: done. 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. + + (* do the retag *) + sim_bind (Retag _ _ _ _ _ _) (Retag _ _ _ _ _ _). + iApply sim_safe_implies. + iIntros ((_ & ot & i & [= ->] & _)). + iPoseProof (value_rel_singleton_source with "Hv") as (sc_t [= ->]) "Hscrel". + iPoseProof (sc_rel_ptr_source with "Hscrel") as ([= ->]) "Htagged". + iApply (sim_retag_fnentry with "Hscrel Hcall"). 1: by cbv. + iIntros (t_i v_t v_s _ Hlen_t Hlen_s) "Hcall #Hvrel Htag_i Hi_t Hi_s". + destruct v_t as [|v_t []]; try done. + destruct v_s as [|v_s []]; try done. iSimpl in "Hcall". + iApply sim_expr_base. + target_apply (Write _ _) (target_write_local with "Htag Ht") "Ht Htag". + 2-3: done. 1: rewrite /write_range bool_decide_true. 2: simpl; lia. 1: rewrite Z.sub_diag /= //. + source_apply (Write _ _) (source_write_local with "Htag Hs") "Hs Htag". + 2: done. 1: rewrite /write_range bool_decide_true. 2: simpl; lia. 1: rewrite Z.sub_diag /= //. + sim_pures. + + (* arbitrary code (call to f) *) + rewrite !subst_result. + sim_apply (Call _ _) (Call _ _) (sim_call _ _ _) ""; first done. + iIntros (r_t_f r_s_f) "Hsamef". sim_pures. + + (* do the activation write *) + source_apply (Copy (Place _ _ _)) (source_copy_local with "Htag Hs") "Hs Htag". 2: done. + 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. + source_pures. source_finish. + target_apply (Copy (Place _ _ _)) (target_copy_local with "Htag Ht") "Ht Htag". 2: done. + 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. + target_pures. + + sim_apply (Write _ _) (Write _ _) (sim_write_activate_protected with "Htag_i Hi_t Hi_s Hcall") "Htag_i Hi_t Hi_s Hcall". 1-3: done. + { intros off Hoff. simpl in *. assert (off = 0)%nat as -> by lia. rewrite /shift_loc /= Z.add_0_r /call_set_in lookup_insert /=. do 2 eexists; split; first done. + by rewrite lookup_insert. } + sim_pures. + + (* arbitrary code (call to g) *) + sim_apply (Call _ _) (Call _ _) (sim_call _ _ _) ""; first done. + iIntros (r_t r_s) "Hsame1". sim_pures. + + (* do the source store *) + source_apply (Copy (Place _ _ _)) (source_copy_local with "Htag Hs") "Hs Htag". 2: done. + 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. + source_pures. + source_apply (Write (Place _ _ _) _) (source_write_protected_active with "Hcall Htag_i Hi_s") "Hi_s Htag_i Hcall". 1,3,4: done. + 1: { rewrite write_range_to_to_list; last (simpl; lia). rewrite Z.sub_diag /= //. } + 2: rewrite lookup_insert //. + 1: intros off (?&?); assert (off = i.2) as -> by (simpl in *; lia); rewrite /shift_loc /= Z.add_0_r lookup_insert; by eexists. + source_pures. source_finish. + + (* cleanup: remove the protector ghost state, make the external locations public, free the local locations*) + sim_apply (Free _) (Free _) (sim_free_local with "Htag Ht Hs") "Htag"; [done..|]. sim_pures. + iApply (sim_make_unique_public with "Hi_t Hi_s Htag_i Hcall []"). 1: by rewrite lookup_insert. + { iIntros "_". iApply value_rel_int. } + iIntros "Htag_i Hcall". iEval (rewrite !fmap_insert !fmap_empty !insert_insert /=) in "Hcall". + iApply (sim_protected_unprotect_public with "Hcall Htag_i"). 1: by rewrite lookup_insert. + iIntros "Hc". iEval (rewrite delete_insert) in "Hc". + sim_apply (EndCall _) (EndCall _) (sim_endcall_own with "Hc") "". + sim_pures. + sim_val. iModIntro. iSplit; first done. + by iApply big_sepL2_nil. +Qed. + +Section closed. + (** Obtain a closed proof of [ctx_ref]. *) + Lemma prot_mutable_reorder_write_up_activated_paper_ctx : ctx_ref prot_mutable_reorder_write_up_activated_paper_opt prot_mutable_reorder_write_up_activated_paper_unopt. + Proof. + set Σ := #[sborΣ]. + apply (log_rel_adequacy Σ)=>?. + apply prot_mutable_reorder_write_up_activated_paper. + Qed. +End closed. + +(* +Check prot_mutable_reorder_write_up_activated_paper_ctx. +Print Assumptions prot_mutable_reorder_write_up_activated_paper_ctx. +*) +(* +prot_mutable_reorder_write_up_activated_paper_ctx + : ctx_ref prot_mutable_reorder_write_up_activated_paper_opt prot_mutable_reorder_write_up_activated_paper_unopt +Axioms: +IndefiniteDescription.constructive_indefinite_description : ∀ (A : Type) (P : A → Prop), (∃ x : A, P x) → {x : A | P x} +Classical_Prop.classic : ∀ P : Prop, P ∨ ¬ P +*) diff --git a/theories/tree_borrows/examples/protected/shared_insert_read.v b/theories/tree_borrows/examples/protected/shared_insert_read.v new file mode 100644 index 0000000000000000000000000000000000000000..bdf9d3bbaf377b4847c6443de70e512338b30dab --- /dev/null +++ b/theories/tree_borrows/examples/protected/shared_insert_read.v @@ -0,0 +1,171 @@ +From simuliris.simulation Require Import lifting. +From simuliris.tree_borrows Require Import proofmode lang adequacy examples.lib. +From iris.prelude Require Import options. + + + +(** Moving read of shared ref up across code that *may* use that ref. *) + +(** This is a variant using protectors. + See delete_read_pubic_escaped_unprotected.v for the original optimization without protectors and with deferred UB. + *) + +(* Assuming x : & i32 *) + +Definition prot_shared_insert_read_unopt : expr := + let: "c" := InitCall in + + (* "x" is the local variable that stores the pointer value "i" *) + let: "x" := new_place sizeof_scalar "i" in + + (* retag_place reborrows the pointer value stored in "x" (which is "i"), + then updates "x" with the new pointer value. + Using a protector here. + *) + retag_place "x" ShrRef TyFrz sizeof_scalar FnEntry "c";; + + (* The unknown code is represented by a call to an unknown function "f" *) + let: "tst" := Call #[ScFnPtr "f"] (#[]) in + (* if tst is negative, if so read from x, otherwise return tst *) + let: "result" := if: "tst" ≤ (#[0])%V + then Copy *{sizeof_scalar} "x" + else "tst" in + + (* Free the local variable *) + Free "x" ;; + + (* Finally, return the read value *) + EndCall "c";; + "result" + . + +Definition prot_shared_insert_read_opt : expr := + let: "c" := InitCall in + let: "x" := new_place sizeof_scalar "i" in + retag_place "x" ShrRef TyFrz sizeof_scalar FnEntry "c";; + let: "tst" := Call #[ScFnPtr "f"] (#[]) in + let: "v" := Copy *{sizeof_scalar} "x" in + let: "result" := if: "tst" ≤ (#[0])%V then "v" else "tst" in + Free "x" ;; + EndCall "c";; + "result" + . + +Lemma prot_shared_insert_read `{sborGS Σ} : + ⊢ log_rel prot_shared_insert_read_opt prot_shared_insert_read_unopt. +Proof. + log_rel. + iIntros "%r_t %r_s #Hrel !# %Ï€ _". + sim_pures. + sim_apply InitCall InitCall sim_init_call "". iIntros (c) "Hcall". iApply sim_expr_base. sim_pures. + + (* new place *) + simpl. source_bind (new_place _ _). + iApply source_red_safe_reach. + { intros. rewrite subst_result. eapply new_place_safe_reach. } + simpl. iIntros "(%v_s & -> & %Hsize)". destruct v_s as [|v_s [|?]]; try done. + iPoseProof (rrel_value_source with "Hrel") as (v_t) "(-> & #Hv)". + iPoseProof (value_rel_length with "Hv") as "%Hlen". destruct v_t as [|v_t [|?]]; try done. + iApply source_red_base. iModIntro. to_sim. + sim_apply (new_place _ _) (new_place _ _) sim_new_place_local "%t %l % % Htag Ht Hs"; first done. + sim_pures. + + target_apply (Copy _) (target_copy_local with "Htag Ht") "Ht Htag". 2: done. 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. + source_apply (Copy _) (source_copy_local with "Htag Hs") "Hs Htag". 2: done. 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. + + (* do the retag *) + sim_bind (Retag _ _ _ _ _ _) (Retag _ _ _ _ _ _). + iApply sim_safe_implies. + iIntros ((_ & ot & i & [= ->] & _)). + iPoseProof (value_rel_singleton_source with "Hv") as (sc_t [= ->]) "Hscrel". + iPoseProof (sc_rel_ptr_source with "Hscrel") as ([= ->]) "Htagged". + iApply (sim_retag_fnentry with "Hscrel Hcall"). 1: by cbv. + iIntros (t_i v_t v_s _ Hlen_t Hlen_s) "Hcall #Hvrel #Htag_i Hi_t Hi_s". + destruct v_t as [|v_t []]; try done. + destruct v_s as [|v_s []]; try done. iSimpl in "Hcall". + iApply sim_expr_base. + target_apply (Write _ _) (target_write_local with "Htag Ht") "Ht Htag". + 2-3: done. 1: rewrite /write_range bool_decide_true. 2: simpl; lia. 1: rewrite Z.sub_diag /= //. + source_apply (Write _ _) (source_write_local with "Htag Hs") "Hs Htag". + 2: done. 1: rewrite /write_range bool_decide_true. 2: simpl; lia. 1: rewrite Z.sub_diag /= //. + sim_pures. + + (* do the call *) + sim_pures. + sim_apply (Call _ _) (Call _ _) (sim_call _ (ValR []) (ValR [])) "". + { iApply big_sepL2_nil. done. } + iIntros (r_t r_s) "#Hfres". sim_pures. + + (* do the target load *) + target_apply (Copy (Place _ _ _)) (target_copy_local with "Htag Ht") "Ht Htag". 2: done. + 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. + target_pures. target_bind (Copy _). + iApply (target_copy_protected with "Hcall Htag_i Hi_t"). 1: done. + 2: simpl; lia. 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. + 2: by rewrite lookup_insert. + { intros off Hoff. simpl in *. rewrite /range'_contains /sizeof_scalar /= in Hoff. assert (off = i.2)%nat as -> by lia. rewrite /shift_loc /= Z.add_0_r /call_set_in lookup_insert /=. by eexists. } + iIntros "Hi_t _ Hcall". target_finish. + sim_pures. simpl. rewrite !subst_result. + + source_bind (BinOp _ _ _). + iApply source_red_safe_implies. 1: eapply (safe_implies_le r_s (ValR [ScInt 0]%V)%V). + iIntros ((zres_s & z2 & -> & [= <-])). + destruct r_t as [[|zres_t []]|]; simpl; try done. + 2: { iExFalso. iPoseProof (big_sepL2_length with "Hfres") as "%HH". done. } + iEval (rewrite /value_rel /= /sc_rel) in "Hfres". iDestruct "Hfres" as "[Hfres _]". + destruct zres_t; try done. iPure "Hfres" as ->. + sim_pures. target_pures. sim_pures. + destruct (bool_decide (zres_s ≤ 0%nat)%Z). + - simpl. target_case; first done. source_case; first done. sim_pures. + (* do the source load *) + source_apply (Copy (Place _ _ _)) (source_copy_local with "Htag Hs") "Hs Htag". 2: done. + 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. + source_pures. source_bind (Copy _). + iApply (source_copy_protected with "Hcall Htag_i Hi_s"). 1: done. + 2: simpl; lia. 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. + 2: by rewrite lookup_insert. + { intros off Hoff. simpl in *. rewrite /range'_contains /sizeof_scalar /= in Hoff. assert (off = i.2)%nat as -> by lia. rewrite /shift_loc /= Z.add_0_r /call_set_in lookup_insert /=. by eexists. } + iIntros "Hi_s _ Hcall". source_finish. + sim_pures. + + (* cleanup: remove the protector ghost state, make the external locations public, free the local locations*) + sim_apply (Free _) (Free _) (sim_free_local with "Htag Ht Hs") "Htag"; [done..|]. sim_pures. + iApply (sim_protected_unprotect_public with "Hcall Htag_i"). 1: by rewrite lookup_insert. + iIntros "Hc". iEval (rewrite delete_insert) in "Hc". + sim_apply (EndCall _) (EndCall _) (sim_endcall_own with "Hc") "". + sim_pures. + sim_val. iModIntro. iSplit; first done. done. + - simpl. target_case; first done. source_case; first done. sim_pures. + + (* cleanup: remove the protector ghost state, make the external locations public, free the local locations*) + sim_apply (Free _) (Free _) (sim_free_local with "Htag Ht Hs") "Htag"; [done..|]. sim_pures. + iApply (sim_protected_unprotect_public with "Hcall Htag_i"). 1: by rewrite lookup_insert. + iIntros "Hc". iEval (rewrite delete_insert) in "Hc". + sim_apply (EndCall _) (EndCall _) (sim_endcall_own with "Hc") "". + sim_pures. + sim_val. iModIntro. iSplit; first done. iApply big_sepL2_singleton. done. +Qed. + + +Section closed. + (** Obtain a closed proof of [ctx_ref]. *) + Lemma prot_shared_insert_read_ctx : ctx_ref prot_shared_insert_read_opt prot_shared_insert_read_unopt. + Proof. + set Σ := #[sborΣ]. + apply (log_rel_adequacy Σ)=>?. + apply prot_shared_insert_read. + Qed. +End closed. + +(* +Check prot_shared_insert_read_ctx. +Print Assumptions prot_shared_insert_read_ctx. +*) +(* +prot_shared_insert_read_ctx + : ctx_ref prot_shared_insert_read_opt prot_shared_insert_read_unopt +Axioms: +IndefiniteDescription.constructive_indefinite_description : ∀ (A : Type) (P : A → Prop), (∃ x : A, P x) → {x : A | P x} +Classical_Prop.classic : ∀ P : Prop, P ∨ ¬ P +*) + diff --git a/theories/tree_borrows/examples/protected/shared_reorder_read_down_escaped.v b/theories/tree_borrows/examples/protected/shared_reorder_read_down_escaped.v index ffa0acf2a0b111dd0b52e550bc1f975f4ce03b54..4574666711631c6c3bfda780ff0df9ad1a63e957 100755 --- a/theories/tree_borrows/examples/protected/shared_reorder_read_down_escaped.v +++ b/theories/tree_borrows/examples/protected/shared_reorder_read_down_escaped.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From simuliris.simulation Require Import lifting. From simuliris.tree_borrows Require Import proofmode lang examples.lib adequacy. From iris.prelude Require Import options. @@ -139,8 +135,10 @@ Section closed. Qed. End closed. +(* Check prot_shared_reorder_read_down_escaped_ctx. Print Assumptions prot_shared_reorder_read_down_escaped_ctx. +*) (* prot_shared_reorder_read_down_escaped_ctx : ctx_ref prot_shared_reorder_read_down_escaped_opt prot_shared_reorder_read_down_escaped_unopt diff --git a/theories/tree_borrows/examples/protected/shared_reorder_read_up_escaped.v b/theories/tree_borrows/examples/protected/shared_reorder_read_up_escaped.v index 303d4c545b56d9f6e59da9c2dd145da4ae6d38ec..71e9eb6e283ba568e76edfeb6733fdfdeeae84fd 100755 --- a/theories/tree_borrows/examples/protected/shared_reorder_read_up_escaped.v +++ b/theories/tree_borrows/examples/protected/shared_reorder_read_up_escaped.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From simuliris.simulation Require Import lifting. From simuliris.tree_borrows Require Import proofmode lang adequacy examples.lib. From iris.prelude Require Import options. @@ -142,9 +138,10 @@ Section closed. apply prot_shared_reorder_read_up_escaped. Qed. End closed. - +(* Check prot_shared_reorder_read_up_escaped_ctx. Print Assumptions prot_shared_reorder_read_up_escaped_ctx. +*) (* prot_shared_reorder_read_up_escaped_ctx : ctx_ref prot_shared_reorder_read_up_escaped_opt prot_shared_reorder_read_up_escaped_unopt diff --git a/theories/tree_borrows/examples/unprotected/mutable_delete_read.v b/theories/tree_borrows/examples/unprotected/mutable_delete_read.v index 64b2cf7e67f2237bc2ba739a81f479335c352453..a8a40a91584eb3fd275cf8cd70883cb864d7bda3 100644 --- a/theories/tree_borrows/examples/unprotected/mutable_delete_read.v +++ b/theories/tree_borrows/examples/unprotected/mutable_delete_read.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From simuliris.simulation Require Import lifting. From simuliris.tree_borrows Require Import proofmode lang adequacy examples.lib. From iris.prelude Require Import options. @@ -115,7 +111,7 @@ Proof. iApply (source_copy_in_simulation with "[] Htag_i Hi_s"). 1: done. 2: simpl; lia. 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. - { iLeft. iApply value_rel_int. } + { iApply value_rel_int. } iIntros (v_res) "Hi_s Htag_i Hv_res". source_pures. source_finish. sim_pures. @@ -138,8 +134,10 @@ Section closed. Qed. End closed. +(* Check unprot_mutable_delete_read_ctx. Print Assumptions unprot_mutable_delete_read_ctx. +*) (* unprot_mutable_delete_read_ctx : ctx_ref unprot_mutable_delete_read_opt unprot_mutable_delete_read_unopt diff --git a/theories/tree_borrows/examples/unprotected/shared_delete_read_escaped.v b/theories/tree_borrows/examples/unprotected/shared_delete_read_escaped.v index 1a18add3ffc301e3cc10c7d4a3ce8fecd54f6682..adc95c916df633dfce7c929950ff8f4e6ab649d1 100644 --- a/theories/tree_borrows/examples/unprotected/shared_delete_read_escaped.v +++ b/theories/tree_borrows/examples/unprotected/shared_delete_read_escaped.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From simuliris.simulation Require Import lifting. From simuliris.tree_borrows Require Import proofmode lang adequacy examples.lib. From iris.prelude Require Import options. @@ -18,12 +14,12 @@ Definition unprot_shared_delete_read_escaped_unopt : expr := then updates "x" with the new pointer value. A [Default] retag is sufficient for this, we don't need the protector. *) retag_place "x" ShrRef TyFrz sizeof_scalar Default #[ScCallId 0];; - (* a "dummy load" -- since we can not insert loads, we must have a load here to so that it can remain in the target *) - (* This load is not used here, but later the target will use the value loaded here *) - Copy *{sizeof_scalar} "x" ;; + (* Note that val is not actually used in the source, but it will be used in the target. *) + let: "val" := Copy *{sizeof_scalar} "x" in (* The unknown code is represented by a call to an unknown function "f", - which does take the pointer value from "x" as an argument. *) - Call #[ScFnPtr "f"] (Copy "x") ;; + which does take the pointer value from "x" as an argument. + To simulate Rust closures, it also takes an arbitrary closure env. *) + Call #[ScFnPtr "f"] (Conc "f_closure_env" (Copy "x")) ;; (* Read the value "v" from the cell pointed to by the pointer in "x" *) let: "v" := Copy *{sizeof_scalar} "x" in @@ -38,8 +34,9 @@ Definition unprot_shared_delete_read_escaped_unopt : expr := Definition unprot_shared_delete_read_escaped_opt : expr := let: "x" := new_place sizeof_scalar "i" in retag_place "x" ShrRef TyFrz sizeof_scalar Default #[ScCallId 0];; - let: "v" := Copy *{sizeof_scalar} "x" in - Call #[ScFnPtr "f"] (Copy "x") ;; + let: "val" := Copy *{sizeof_scalar} "x" in + Call #[ScFnPtr "f"] (Conc "f_closure_env" (Copy "x")) ;; + let: "v" := "val" in Free "x" ;; "v" . @@ -49,8 +46,9 @@ Lemma unprot_shared_delete_read_escaped `{sborGS Σ} : ⊢ log_rel unprot_shared_delete_read_escaped_opt unprot_shared_delete_read_escaped_unopt. Proof. log_rel. - iIntros "%r_t %r_s #Hrel !# %Ï€ _". + iIntros "%closure_env_t %closure_env_s #Hclosure_env_rel %r_t %r_s #Hrel !# %Ï€ _". sim_pures. + rewrite !subst_result. (* new place *) simpl. source_bind (new_place _ _). @@ -102,8 +100,14 @@ Proof. 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. source_apply (Copy _) (source_copy_local with "Htag Hs") "Hs Htag". 2: done. 1: rewrite read_range_heaplet_to_list // Z.sub_diag /= //. sim_pures. - sim_apply (Call _ _) (Call _ _) (sim_call _ (ValR [ScPtr i _]) (ValR [ScPtr i _])) "". - { iApply big_sepL2_singleton. iFrame "Htag_i". done. } + rewrite !subst_result. + source_bind (Conc _ _). + iApply source_red_safe_implies. 1: eapply irred_conc with (r2 := ValR _). + iIntros ((closure_env_s_v & v2 & -> & [= <-])). + destruct closure_env_t as [closure_env_t_v|]; last done. + source_pures. to_sim. sim_pures. + sim_apply (Call _ _) (Call _ _) (sim_call _ (ValR _) (ValR _)) "". + { iApply big_sepL2_app; first iAssumption. iApply big_sepL2_singleton. iFrame "Htag_i". done. } iIntros (r_t r_s) "_". sim_pures. (* source load (not existing in the target) *) @@ -134,8 +138,10 @@ Section closed. Qed. End closed. +(* Check unprot_shared_delete_read_escaped_ctx. Print Assumptions unprot_shared_delete_read_escaped_ctx. +*) (* unprot_shared_delete_read_escaped_ctx : ctx_ref unprot_shared_delete_read_escaped_opt unprot_shared_delete_read_escaped_unopt diff --git a/theories/tree_borrows/examples/unprotected/shared_delete_read_escaped_coinductive.v b/theories/tree_borrows/examples/unprotected/shared_delete_read_escaped_coinductive.v index 4d17427ef202db8f0148b0da752a144768e1c3a8..72891e222eaeb2d65559044c15dd696d52cb1bf3 100755 --- a/theories/tree_borrows/examples/unprotected/shared_delete_read_escaped_coinductive.v +++ b/theories/tree_borrows/examples/unprotected/shared_delete_read_escaped_coinductive.v @@ -323,9 +323,10 @@ Section closed. Qed. End closed. - +(* Check unprot_shared_delete_read_escaped_coinductive_ctx. Print Assumptions unprot_shared_delete_read_escaped_coinductive_ctx. +*) (* unprot_shared_delete_read_escaped_coinductive_ctx : ctx_ref unprot_shared_delete_read_escaped_coinductive_opt unprot_shared_delete_read_escaped_coinductive_unopt diff --git a/theories/tree_borrows/expr_semantics.v b/theories/tree_borrows/expr_semantics.v index 330bbabfc65dc1995a68db26cf3fea8bd20a493f..d658e9918ce642613c8f19e53596f6b20bf2b110 100755 --- a/theories/tree_borrows/expr_semantics.v +++ b/theories/tree_borrows/expr_semantics.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From Equations Require Import Equations. From iris.prelude Require Import prelude options. From stdpp Require Export gmap. @@ -27,12 +23,8 @@ Fixpoint subst (x : string) (es : expr) (e : expr) : expr := | Write e1 e2 => Write (subst x es e1) (subst x es e2) | Alloc T => Alloc T | Free e => Free (subst x es e) - (* | CAS e0 e1 e2 => CAS (subst x es e0) (subst x es e1) (subst x es e2) *) - (* | AtomWrite e1 e2 => AtomWrite (subst x es e1) (subst x es e2) *) - (* | AtomRead e => AtomRead (subst x es e) *) | Deref e T => Deref (subst x es e) T | Ref e => Ref (subst x es e) - (* | Field e path => Field (subst x: es e) path *) | Retag e1 e2 newp im sz kind => Retag (subst x es e1) (subst x es e2) newp im sz kind | Let x1 e1 e2 => Let x1 (subst x es e1) @@ -40,7 +32,6 @@ Fixpoint subst (x : string) (es : expr) (e : expr) : expr := | Case e el => Case (subst x es e) (fmap (subst x es) el) | Fork e => Fork (subst x es e) | While e1 e2 => While (subst x es e1) (subst x es e2) - (* | SysCall id => SysCall id *) end. (* formal argument list substitution *) @@ -111,7 +102,6 @@ Inductive ectx_item := | FreeEctx | DerefEctx (sz : nat) | RefEctx -(* | FieldEctx (path : list nat) *) | RetagREctx (e1 : expr) (pk : pointer_kind) (im : interior_mut) (sz : nat) (kind : retag_kind) | RetagLEctx (r2 : result) (pk : pointer_kind) (im : interior_mut) (sz : nat) (kind : retag_kind) | LetEctx (x : binder) (e2 : expr) @@ -136,7 +126,6 @@ Definition fill_item (Ki : ectx_item) (e : expr) : expr := | FreeEctx => Free e | DerefEctx T => Deref e T | RefEctx => Ref e - (* | FieldEctx path => Field e path *) | RetagLEctx r2 newp im sz kind => Retag e (of_result r2) newp im sz kind | RetagREctx e1 newp im sz kind => Retag e1 e newp im sz kind | LetEctx x e2 => Let x e e2 @@ -465,15 +454,9 @@ Inductive pure_expr_step (P : prog) (h : mem) : expr → expr → list expr → pure_expr_step P h (Conc (Val v1) (Val v2)) (Val (v1 ++ v2)) [] | RefPS l lbor T : - (* is_Some (h !! l) → *) pure_expr_step P h (Ref (Place l lbor T)) #[ScPtr l lbor] [] -| DerefPS l lbor T - (* (DEFINED: ∀ (i: nat), (i < tsize T)%nat → l +â‚— i ∈ dom h) *) : +| DerefPS l lbor T : pure_expr_step P h (Deref #[ScPtr l lbor] T) (Place l lbor T) [] -(* | FieldBS l lbor T path off T' - (FIELD: field_access T path = Some (off, T')) : - pure_expr_step FNs h (Field (Place l lbor T) path) - SilentEvt (Place (l +â‚— off) lbor T') *) | LetPS x e1 e2 e' : is_Some (to_result e1) → subst' x e1 e2 = e' → @@ -506,10 +489,12 @@ Inductive mem_expr_step (h: mem) : expr → event → mem → expr → list expr | CopyBS blk l lbor sz (v: value) (READ: read_mem (blk, l) sz h = Some v) : mem_expr_step h (Copy (Place (blk, l) lbor sz)) (CopyEvt blk lbor (l, sz) v) h (Val v) [] -| FailedCopyBS blk l lbor sz +(* This was a poison semantics for failing reads. We have removed this to be + closer to the actual semantics described in Tree Borrows. + | FailedCopyBS blk l lbor sz (READ: is_Some (read_mem (blk, l) sz h)) : (* failed copies lead to poison, but still of the appropriate length *) - mem_expr_step h (Copy (Place (blk, l) lbor sz)) (FailedCopyEvt blk lbor (l, sz)) h (Val $ replicate sz ScPoison) [] + mem_expr_step h (Copy (Place (blk, l) lbor sz)) (FailedCopyEvt blk lbor (l, sz)) h (Val $ replicate sz ScPoison) []*) | WriteBS blk l lbor sz v (LEN: length v = sz) (DEFINED: ∀ (i: nat), (i < length v)%nat → (blk,l) +â‚— i ∈ dom h) : @@ -524,17 +509,17 @@ Inductive mem_expr_step (h: mem) : expr → event → mem → expr → list expr (AllocEvt blk lbor (0, sz)) (init_mem (blk, 0) sz h) (Place (blk, 0) lbor sz) [] | DeallocBS blk l (sz:nat) lbor : - (* FIXME: l here is an offset. But we usually want to deallocate at offset 0, right? *) - (* FIXME: This is wrong because it allows double-free of zero-sized allocations - Possible solutions: - - Change the heap from `gmap loc scalar` to `gmap blk (gmap Z scalar)` - - Require `sz > 0` <- probably this - - special case for TB where if the size is zero we don't add a new tree + (* WARNING: If we are not careful here, it could allow double-free of zero-sized allocations. + Possible solutions that we have considered include + - changing the heap from `gmap loc scalar` to `gmap blk (gmap Z scalar)` + - requiring `sz . 0` + - having a special case for TB where if the size is zero we don't add a new tree. + + We go for the second one and forbid zero-sized allocations, at the level of + `AllocIS` in `bor_semantics`. + FIXME: We could potentially be able to actually *prove* here that `sz > 0` + if we added this to `state_wf`. Until then it is UB to deallocate a zero-sized. *) - (* Actual solution: We forbid zero-sized allocations (see AllocIS in bor_semantics). - If we track that in state_wf, we should be able to prove that sz > 0 here, - instead of making it UB. - TODO actually add it to state_wf, until then it is UB *) (sz > 0)%nat → (∀ m, is_Some (h !! ((blk,l) +â‚— m)) ↔ 0 ≤ m < sz) → mem_expr_step @@ -546,8 +531,4 @@ Inductive mem_expr_step (h: mem) : expr → event → mem → expr → list expr h (Retag #[ScPtr l otag] #[ScCallId cid] pk im sz kind) (RetagEvt l.1 (l.2, sz) otag ntag pk im cid kind) h #[ScPtr l ntag] [] - -(* observable behavior *) -(* | SysCallBS id h: - expr_step (SysCall id) h (SysCallEvt id) (Lit LitPoison) h [] *) . diff --git a/theories/tree_borrows/helpers.v b/theories/tree_borrows/helpers.v index 7e2a01e0cc0579c10bdf5637f0f5a769c013fdfa..2da99c05e8514509d13a6dfe80edabc5d135ba84 100755 --- a/theories/tree_borrows/helpers.v +++ b/theories/tree_borrows/helpers.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From Coq Require Import ssreflect. From stdpp Require Export list gmap. From iris.prelude Require Export prelude. diff --git a/theories/tree_borrows/lang.v b/theories/tree_borrows/lang.v index 0e10eacfd88c0a99b8b7a6900ae61f686c9c2289..89d58619b8e159d3b4a1fdfbe481f498ed87e04e 100755 --- a/theories/tree_borrows/lang.v +++ b/theories/tree_borrows/lang.v @@ -1,6 +1,5 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) +(** This file manages the interface between the expression semantics and + the borrow semantics. *) From simuliris.simulation Require Export language. From iris.algebra Require Import ofe. @@ -15,7 +14,7 @@ Module bor_lang. Record state := mkState { (* Heap of scalars *) shp : mem; - (* Stacked borrows for the heap *) + (* Borrow trees for each allocation of the heap *) strs : trees; (* Set of active call ids *) scs : call_id_set; diff --git a/theories/tree_borrows/lang_base.v b/theories/tree_borrows/lang_base.v index 4a784959631bd215e699e1ae19837c31e75475b9..d522aa9cc71173ad6f7ef1866507e434b09843c1 100755 --- a/theories/tree_borrows/lang_base.v +++ b/theories/tree_borrows/lang_base.v @@ -191,7 +191,6 @@ Definition item_lookup (it : item) (l : Z) := Definition trees := gmap block (tree item). (** Retag kinds *) -(* FIXME: simplify related stuff *) Inductive retag_kind := FnEntry | Default. (** Language base constructs *) @@ -200,20 +199,9 @@ Inductive retag_kind := FnEntry | Default. Inductive bin_op := | AddOp (* + addition *) | SubOp (* - subtraction *) -(* | MulOp (* * multiplication *) - | DivOp (* / division *) - | RemOp (* % modulus *) - | BitXorOp (* ^ bit xor *) - | BitAndOp (* & bit and *) - | BitOrOp (* | bit or *) - | ShlOp (* << shift left *) - | ShrOp (* >> shift right *) *) | EqOp (* == equality *) | LtOp (* < less than *) | LeOp (* <= less than or equal to *) -(* | NeOp (* != not equal to *) - | GeOp (* >= greater than or equal to *) - | GtOp (* > greater than *) *) | OffsetOp (* . offset *) . @@ -307,18 +295,11 @@ Inductive expr := presenting the location that `e` points to. The location has the kind and size of `ptr`. *) | Ref (e : expr) (* Turn a place `e` into a pointer value. *) -(* | Field (e: expr) (path: list nat)(* Create a place that points to a component - of the place `e`. `path` defines the path - through the type. *) *) (* mem op *) | Copy (e : expr) (* Read from the place `e` *) | Write (e1 e2 : expr) (* Write the value `e2` to the place `e1` *) | Alloc (sz : nat) (* Allocate a place of type `T` *) | Free (e : expr) (* Free the place `e` *) -(* atomic mem op *) -(* | CAS (e0 e1 e2 : expr) *) (* CAS the value `e2` for `e1` to the place `e0` *) -(* | AtomWrite (e1 e2: expr) *) -(* | AtomRead (e: expr) *) (* retag *) (* Retag the memory pointed to by `e1` with retag kind `kind`, for call_id `e2`. The new pointer should have pointer kind pk. *) | Retag (e1 : expr) (e2 : expr) (pk : pointer_kind) (im : interior_mut) (sz : nat) (kind : retag_kind) @@ -330,8 +311,6 @@ Inductive expr := | Fork (e : expr) (* While *) | While (e1 e2 : expr) -(* observable behavior *) -(* | SysCall (id: nat) *) . Bind Scope expr_scope with expr. @@ -356,15 +335,15 @@ Arguments While _%_E _%_E. (** Closedness *) Fixpoint is_closed (X : list string) (e : expr) : bool := match e with - | Val _ | Place _ _ _ | Alloc _ | InitCall (* | SysCall _ *) => true + | Val _ | Place _ _ _ | Alloc _ | InitCall => true | Var x => bool_decide (x ∈ X) | BinOp _ e1 e2 | Write e1 e2 | While e1 e2 | Conc e1 e2 | Proj e1 e2 | Call e1 e2 | Retag e1 e2 _ _ _ _ => is_closed X e1 && is_closed X e2 | Let x e1 e2 => is_closed X e1 && is_closed (x :b: X) e2 | Case e el => is_closed X e && forallb (is_closed X) el - | Fork e | Copy e | Deref e _ | Ref e (* | Field e _ *) - | Free e | EndCall e (* | AtomRead e | Fork e *) + | Fork e | Copy e | Deref e _ | Ref e + | Free e | EndCall e => is_closed X e end. @@ -446,30 +425,11 @@ Qed. (** Main state: a heap of scalars, each with an associated lock to detect data races. *) Definition mem := gmap loc scalar. -(** Internal events *) - -(* Per-allocation events. - This is only useful during the proofs against the operational semantics: - if we drop support for [disjoint.v] we should also delete this definition. *) -Inductive bor_local_event := - | AccessBLEvt (kind : access_kind) (tg : tag) (range : Z * nat) - | InitCallBLEvt (cid : call_id) - | EndCallBLEvt (cid : call_id) - | RetagBLEvt (tgp tg : tag) (pk : pointer_kind) (im : interior_mut) (c : call_id) (rk : retag_kind) - | SilentBLEvt. - -(* Events in all their generality. - We use the point of view adopted by Stacked Borrows and regarded by LLVM - as acceptable which is to make FAILED READS NOT UB. - A failed read has its own event [FailedCopyEvt] which returns poison - instead of triggering immediate UB. This is assumed to be a sound change - w.r.t. the semantics and is expected to allow proving more optimizations - (they would still be true, but they wouldn't be *provable* with our means) *) +(* Arbitrary borrow events. *) Inductive event := | AllocEvt (alloc : block) (lbor : tag) (range : Z * nat) | DeallocEvt (alloc : block) (lbor: tag) (range : Z * nat) | CopyEvt (alloc : block) (lbor : tag) (range : Z * nat) (v : value) -| FailedCopyEvt (alloc : block) (lbor : tag) (range : Z * nat) | WriteEvt (alloc : block) (lbor : tag) (range : Z * nat) (v : value) | InitCallEvt (c : call_id) | EndCallEvt (c : call_id) diff --git a/theories/tree_borrows/locations.v b/theories/tree_borrows/locations.v index 1b91d57ce2075557fdf1dbe0a800ce21fd3d7881..c2feb5335b2ffd3f7ad7f971a37e195a028f9ef2 100755 --- a/theories/tree_borrows/locations.v +++ b/theories/tree_borrows/locations.v @@ -1,6 +1,6 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) +(** Internal representation of memory. + We opt for a view in which a location is composed of + an allocation id and an offset into that allocation. *) From iris.prelude Require Import prelude. From iris.prelude Require Import options. diff --git a/theories/tree_borrows/logical_state.v b/theories/tree_borrows/logical_state.v index 6ccfadcc1ca53f6b429a5cf29976a92051ed5d55..48e8848e018b6df2ee5d6a5a292d7f15d6c67e0c 100755 --- a/theories/tree_borrows/logical_state.v +++ b/theories/tree_borrows/logical_state.v @@ -393,13 +393,12 @@ Section heap_defs. ∧ ((item_lookup it l.2).(initialized) = PermInit → (item_lookup it l.2).(perm) ≠Disabled) end. - (* FIXME: merge the two tk_unq ? *) + (* FIXME: Refactor potential: merge the two tk_unq *) Lemma bor_state_pre_unq_or l t tk σ : (tk = tk_unq tk_act ∨ tk = tk_unq tk_res) → bor_state_pre l t tk σ = bor_state_pre_unq l t σ. Proof. intros [-> | ->]; done. Qed. - (* TODO: we still want that the children are disabled and the cousins are not active even when this tag is frozen !protected. So perhaps we need 2 case distinctions here? *) Definition bor_state_post_unq (l : loc) (t : tag) (σ : state) it tr tkk:= let P := ((item_lookup it l.2).(perm) = Frozen → protector_is_active it.(iprot) σ.(scs)) in ( P → @@ -449,38 +448,6 @@ Section heap_defs. Definition loc_controlled (l : loc) (t : tag) (tk : tag_kind) (sc : scalar) (σ : state) := (bor_state_pre l t tk σ → bor_state_own l t tk σ ∧ σ.(shp) !! l = Some sc). -(* Lemma loc_controlled_local l t sc σ : - loc_controlled l t tk_local sc σ → - σ.(sst) !! l = Some [mkItem Unique (Tagged t) None] ∧ - σ.(shp) !! l = Some sc. - Proof. intros Him. specialize (Him I) as (Hbor & Hmem). split;done. Qed. - - Lemma loc_controlled_unq l t sc s σ : - loc_controlled l t tk_unq sc σ → - σ.(sst) !! l = Some s → - (∃ pm opro, mkItem pm (Tagged t) opro ∈ s ∧ pm ≠Disabled) → - (∃ s' op, s = (mkItem Unique (Tagged t) op) :: s') ∧ - σ.(shp) !! l = Some sc. - Proof. - intros Him Hstk (pm & opro & Hpm). - edestruct Him as (Hown & ?). { rewrite /bor_state_pre. eauto. } - split; last done. - destruct Hown as (st' & opro' & st'' & Hst' & ->). simplify_eq. eauto. - Qed. - - Lemma loc_controlled_pub l t sc σ s : - loc_controlled l t tk_pub sc σ → - σ.(sst) !! l = Some s → - (∃ pm opro, mkItem pm (Tagged t) opro ∈ s ∧ pm ≠Disabled) → - t ∈ active_SRO s ∧ - σ.(shp) !! l = Some sc. - Proof. - intros Him Hst (pm & opro & Hin & Hpm). - edestruct Him as (Hown & ?). { rewrite /bor_state_pre; eauto 8. } - split; last done. destruct Hown as (st' & Hst' & Hsro). - simplify_eq. eauto. - Qed. *) - Lemma loc_controlled_mem_insert_ne l l' t tk sc sc' σ : l ≠l' → loc_controlled l t tk sc σ → @@ -497,82 +464,6 @@ Section heap_defs. intros Him Hpre. apply Him in Hpre as [Hown Hmem]. split; first done. rewrite lookup_insert; done. Qed. -(* - Section local. - (** Facts about local tags *) - Lemma loc_controlled_local_unique l t t' sc sc' σ : - loc_controlled l t tk_local sc σ → - loc_controlled l t' tk_local sc' σ → - t' = t ∧ sc' = sc. - Proof. - intros Hcontrol Hcontrol'. specialize (Hcontrol I) as [Hown Hmem]. - specialize (Hcontrol' I) as [Hown' Hmem']. - split; last by simplify_eq. - move : Hown Hown'. rewrite /bor_state_own // => -> [=] //. - Qed. - - Lemma loc_controlled_local_pre l t t' tk' sc σ : - loc_controlled l t tk_local sc σ → - bor_state_pre l t' tk' σ → - tk' = tk_local ∨ t' = t. - Proof. - intros [Heq _]%loc_controlled_local. - destruct tk'; last by eauto. - - intros (st' & pm & opro & Hst & Hin & Hpm). - move : Hst Hin. rewrite Heq. - move => [= <-] /elem_of_list_singleton [=]; eauto. - - intros (st' & pm & opro & Hst & Hin & Hpm). - move : Hst Hin. rewrite Heq. - move => [= <-] /elem_of_list_singleton [=]; eauto. - Qed. - Lemma bor_state_local_own_exclusive l t t' tk' σ : - bor_state_own l t tk_local σ → - bor_state_own l t' tk' σ → - (tk' = tk_unq ∨ tk' = tk_local) ∧ t = t'. - Proof. - intros Heq. destruct tk'. - - move => [st' []]. rewrite Heq => [= <-] //. - - move => [st' [Heq' [opro [st'' ]]]]. move : Heq'. rewrite Heq => [= <-] [= ->] //; eauto. - - rewrite /bor_state_own Heq => [=]; eauto. - Qed. - Lemma bor_state_unq_own_exclusive l t t' tk' σ : - bor_state_own l t tk_unq σ → - bor_state_own l t' tk' σ → - (tk' = tk_unq ∨ tk' = tk_local) ∧ t = t'. - Proof. - intros (stk & Hstk & (opro & stk' & ->)). - destruct tk'; simpl. - - intros (stk'' & Hstk'' & Hact). rewrite Hstk in Hstk''. injection Hstk'' as [= <-]. - simpl in Hact. done. - - intros (stk'' & Hstk'' & (opro' & stk''' & ->)). - rewrite Hstk'' in Hstk. injection Hstk as [= -> -> ->]. eauto. - - rewrite Hstk. intros [= -> -> ->]. eauto. - Qed. - - (* having local ownership of a location is authoritative, in the sense that we can update memory without hurting other tags that control this location. *) - Lemma loc_controlled_local_authoritative l t t' tk' sc sc' σ f : - loc_controlled l t tk_local sc (state_upd_mem f σ) → - loc_controlled l t' tk' sc' σ → - t ≠t' → - loc_controlled l t' tk' sc' (state_upd_mem f σ). - Proof. - intros Hcontrol Hcontrol' Hneq [Hown Hmem]%Hcontrol'. split; first done. - edestruct (bor_state_local_own_exclusive l t t' tk' (state_upd_mem f σ)) as [_ <-]; [apply Hcontrol |..]; done. - Qed. - - Lemma loc_controlled_protected_authoritative l t t' tk' sc sc' σ f c : - loc_protected_by (state_upd_mem f σ) t l c → - loc_controlled l t tk_unq sc (state_upd_mem f σ) → - loc_controlled l t' tk' sc' σ → - t ≠t' → - loc_controlled l t' tk' sc' (state_upd_mem f σ). - Proof. - intros Hprot Hcontrol Hcontrol' Hneq [Hown Hmem]%Hcontrol'. split; first done. - specialize (loc_protected_bor_state_pre _ _ _ _ tk_unq Hprot) as Hpre. - apply Hcontrol in Hpre as [Hown' Hmem']. - edestruct (bor_state_unq_own_exclusive l t t' tk' (state_upd_mem f σ)) as [_ <-]; done. - Qed. - End local. *) (** Domain agreement for the two heap views for source and target *) Definition dom_agree_on_tag (M_t M_s : gmap (tag * block) (gmap Z scalar)) (t : tag) := @@ -681,56 +572,6 @@ Section heap_defs. + eapply H3r. rewrite /heaplet_lookup HMo /= HH //. Qed. -(* - Lemma dom_agree_on_tag_upd_ne_source M_t M_s t t' l sc : - t ≠t' → - dom_agree_on_tag M_t M_s t' → - dom_agree_on_tag M_t (<[(t, l) := sc]> M_s) t'. - Proof. - intros Hneq [Htgt Hsrc]. split => l'' Hsome. - - apply lookup_insert_is_Some. right. split; first congruence. by apply Htgt. - - apply Hsrc. move : Hsome. rewrite lookup_insert_is_Some. by intros [[= -> <-] | [_ ?]]. - Qed. - Lemma dom_agree_on_tag_upd_target M_t M_s t l sc : - is_Some (M_t !! (t, l)) → - dom_agree_on_tag M_t M_s t → - dom_agree_on_tag (<[(t, l) := sc]> M_t) M_s t. - Proof. - intros Hs [Htgt Hsrc]. split => l''. - - rewrite lookup_insert_is_Some. intros [[= <-] | [_ ?]]; by apply Htgt. - - intros Hsome. rewrite lookup_insert_is_Some'. right; by apply Hsrc. - Qed. - Lemma dom_agree_on_tag_upd_source M_t M_s t l sc : - is_Some (M_s !! (t, l)) → - dom_agree_on_tag M_t M_s t → - dom_agree_on_tag M_t (<[(t, l) := sc]> M_s) t. - Proof. - intros Hs [Htgt Hsrc]. split => l''. - - intros Hsome. rewrite lookup_insert_is_Some'. right; by apply Htgt. - - rewrite lookup_insert_is_Some. intros [[= <-] | [_ ?]]; by apply Hsrc. - Qed. - Lemma dom_agree_on_tag_lookup_target M_t M_s t l : - dom_agree_on_tag M_t M_s t → is_Some (M_t !! (t, l)) → is_Some (M_s !! (t, l)). - Proof. intros Hag Hsome. apply Hag, Hsome. Qed. - Lemma dom_agree_on_tag_lookup_source M_t M_s t l : - dom_agree_on_tag M_t M_s t → is_Some (M_s !! (t, l)) → is_Some (M_t !! (t, l)). - Proof. intros Hag Hsome. apply Hag, Hsome. Qed. - - Lemma dom_agree_on_tag_difference M1_t M1_s M2_t M2_s t : - dom_agree_on_tag M1_t M1_s t → dom_agree_on_tag M2_t M2_s t → - dom_agree_on_tag (M1_t ∖ M2_t) (M1_s ∖ M2_s) t. - Proof. - intros [H1a H1b] [H2a H2b]. split; intros l. - all: rewrite !lookup_difference_is_Some !eq_None_not_Some; naive_solver. - Qed. - - Lemma dom_agree_on_tag_union M1_t M1_s M2_t M2_s t : - dom_agree_on_tag M1_t M1_s t → dom_agree_on_tag M2_t M2_s t → - dom_agree_on_tag (M1_t ∪ M2_t) (M1_s ∪ M2_s) t. - Proof. - intros [H1a H1b] [H2a H2b]. split; intros l; rewrite !lookup_union_is_Some; naive_solver. - Qed. *) - Definition dom_unique_per_tag (M : gmap (tag * block) (gmap Z scalar)) : Prop := ∀ tg l1 l2, (tg, l1) ∈ dom M → (tg, l2) ∈ dom M → l1 = l2. @@ -757,12 +598,6 @@ Definition tk_to_frac (tk : tag_kind) := | tk_pub => DfracDiscarded | _ => DfracOwn 1 end. -(* -Notation "l '↦t[' tk ']{' t } sc" := (ghost_map_elem heap_view_target_name (t, l) (tk_to_frac tk) sc) - (at level 20, format "l ↦t[ tk ]{ t } sc") : bi_scope. -Notation "l '↦s[' tk ']{' t } sc" := (ghost_map_elem heap_view_source_name (t, l) (tk_to_frac tk) sc) - (at level 20, format "l ↦s[ tk ]{ t } sc") : bi_scope. -*) Section public_call_ids. Context `{bor_stateGS Σ}. @@ -1385,124 +1220,6 @@ Proof. rewrite IH. 2: lia. f_equal. f_equal. lia. Qed. - - -(* - -Lemma array_tag_map_lookup1 l t v t' l' r : - array_tag_map l t v !! (t', l') = Some r → - t' = t ∧ l.1 = l'.1 ∧ l.2 ≤ l'.2 < l.2 + length v. -Proof. - induction v as [ | sc v IH] in l,r |-*. - - simpl. rewrite lookup_empty. intros [=]. - - simpl. rewrite lookup_insert_Some. move => [[[= <- <-] Heq] | [Hneq Ht]]. - + split; first done. lia. - + move : (IH (l +â‚— 1) ltac:(eauto) ltac:(eauto)). destruct l. simpl. intros (H1&H2); split; first done; lia. -Qed. -Lemma array_tag_map_lookup1_is_Some l t v t' l' : - is_Some (array_tag_map l t v !! (t', l')) → - t' = t ∧ l.1 = l'.1 ∧ l.2 ≤ l'.2 < l.2 + length v. -Proof. - intros [x Hx]. by eapply array_tag_map_lookup1. -Qed. - -Lemma array_tag_map_lookup2 l t v t' l' : - is_Some (array_tag_map l t v !! (t', l')) → - t' = t ∧ ∃ i, (i < length v)%nat ∧ l' = l +â‚— i. -Proof. - intros [x (-> & H1 & H2)%array_tag_map_lookup1]. - split; first done. exists (Z.to_nat (l'.2 - l.2)). - destruct l, l'; rewrite /shift_loc; simpl in *. split. - - lia. - - apply pair_equal_spec. split; lia. -Qed. - -Lemma array_tag_map_lookup_Some l t v (i : nat) : - (i < length v)%nat → - array_tag_map l t v !! (t, l +â‚— i) = v !! i. -Proof. - induction v as [ | sc v IH] in l, i |-*. - - simpl. lia. - - simpl. intros Hi. destruct i as [ | i]. - + rewrite shift_loc_0_nat. rewrite lookup_insert. done. - + rewrite lookup_insert_ne; first last. { destruct l; simpl; intros [= ?]; lia. } - move : (IH (l +â‚— 1) i ltac:(lia)). rewrite shift_loc_assoc. - by replace (Z.of_nat (S i)) with (1 + i) by lia. -Qed. - -Lemma array_tag_map_lookup_None t t' l v : - t ≠t' → ∀ l', array_tag_map l t v !! (t', l') = None. -Proof. - intros Hneq l'. destruct (array_tag_map l t v !! (t', l')) eqn:Harr; last done. - specialize (array_tag_map_lookup1 l t v t' l' ltac:(eauto) ltac:(eauto)) as [Heq _]; congruence. -Qed. - -Lemma array_tag_map_lookup_None' l t v l' : - (∀ i:nat, (i < length v)%nat → l +â‚— i ≠l') → - array_tag_map l t v !! (t, l') = None. -Proof. - intros Hneq. destruct (array_tag_map _ _ _ !! _) eqn:Heq; last done. exfalso. - specialize (array_tag_map_lookup2 l t v t l' ltac:(eauto)) as [_ (i & Hi & ->)]. - eapply Hneq; last reflexivity. done. -Qed. - -Lemma array_tag_map_lookup_None2 l t t' v l' : - array_tag_map l t v !! (t', l') = None → - t ≠t' ∨ (∀ i: nat, (i < length v)%nat → l +â‚— i ≠l'). -Proof. - induction v as [ | sc v IH] in l |-*; simpl. - - intros _. right. intros i Hi; lia. - - rewrite lookup_insert_None. intros [Ha%IH Hneq]. - destruct Ha; first by eauto. move: Hneq. rewrite pair_equal_spec not_and_l. - intros [ ? | Hneq]; first by eauto. - right. intros i Hi. destruct i as [ | i]. - + rewrite shift_loc_0_nat. done. - + replace (Z.of_nat (S i)) with (1 + i)%Z by lia. rewrite -shift_loc_assoc. - eauto with lia. -Qed. - -Lemma dom_agree_on_tag_array_tag_map l t v_t v_s : - length v_t = length v_s → - dom_agree_on_tag (array_tag_map l t v_t) (array_tag_map l t v_s) t. -Proof. - intros Hlen. split; intros l'. - - intros (_ & (i & Hi & ->))%array_tag_map_lookup2. rewrite array_tag_map_lookup_Some; last lia. - apply lookup_lt_is_Some_2. lia. - - intros (_ & (i & Hi & ->))%array_tag_map_lookup2. rewrite array_tag_map_lookup_Some; last lia. - apply lookup_lt_is_Some_2. lia. -Qed. - -(** Array update lemmas for the heap views *) -Lemma ghost_map_array_tag_lookup `{!bor_stateGS Σ} (γh : gname) (q : Qp) (M : gmap (tag * block) (gmap Z scalar)) (v : list scalar) (t : tag) (l : loc) dq : - ghost_map_auth γh q M -∗ - ([∗ list] i ↦ sc ∈ v, ghost_map_elem γh (t, l +â‚— i) dq sc) -∗ - ⌜∀ i : nat, (i < length v)%nat → M !! (t, l +â‚— i) = v !! iâŒ. -Proof. - iIntros "Hauth Helem". iInduction v as [ |sc v ] "IH" forall (l) "Hauth Helem". - - iPureIntro; cbn. lia. - - rewrite big_sepL_cons. iDestruct "Helem" as "[Hsc Hscs]". - iPoseProof (ghost_map_lookup with "Hauth Hsc") as "%Hl". - iDestruct ("IH" $! (l +â‚— 1) with "Hauth [Hscs]") as "%IH". - { iApply (big_sepL_mono with "Hscs"). intros i sc' Hs. cbn. rewrite shift_loc_assoc. - replace (Z.of_nat $ S i) with (1 + i)%Z by lia. done. } - iPureIntro. intros i Hle. destruct i as [|i]; first done. - replace (Z.of_nat $ S i) with (1 + i)%Z by lia. cbn in *. rewrite -(IH i); last lia. - by rewrite shift_loc_assoc. -Qed. - -Lemma array_tag_map_union_commute (l : loc) (sc : scalar) (t : tag) (v : list scalar) (M : gmap (tag * block) (gmap Z scalar)) (i : Z) : - i > 0 → - <[(t, l) := sc]> (array_tag_map (l +â‚— i) t v) ∪ M = array_tag_map (l +â‚— i) t v ∪ (<[(t, l) := sc]> M). -Proof. - intros Hi. induction v as [ | sc' v IH] in l, i, Hi |-*; simpl. - - rewrite insert_union_singleton_l. rewrite -map_union_assoc. rewrite !map_empty_union. - by rewrite insert_union_singleton_l. - - rewrite insert_commute. 2: { intros [= Heq]. destruct l; simpl in *. injection Heq. lia. } - rewrite shift_loc_assoc. rewrite -insert_union_l. rewrite (IH l (i + 1)%Z); last lia. - rewrite -insert_union_l. done. -Qed. -*) - Lemma ghost_map_array_tag_update `{!bor_stateGS Σ} (γh : gname) (M : gmap (tag * block) (gmap Z scalar)) (v v' : list scalar) (t : tag) (l : loc) : length v = length v' → ghost_map_auth γh 1 M -∗ @@ -1529,66 +1246,6 @@ Proof. all: by iFrame. Qed. -(* -Lemma ghost_map_array_tag_insert `{!bor_stateGS Σ} (γh : gname) (M : gmap (tag * block) (gmap Z scalar)) (v : list scalar) (t : tag) (l : loc) : - (∀ i : nat, (i < length v)%nat → M !! (t, l +â‚— i) = None) → - ghost_map_auth γh 1 M ==∗ - ([∗ list] i ↦ sc ∈ v, ghost_map_elem γh (t, l +â‚— i) (DfracOwn 1) sc) ∗ - ghost_map_auth γh 1 (array_tag_map l t v ∪ M). -Proof. - iIntros (Hnone) "Hauth". iInduction v as [ | sc v ] "IH" forall (M l Hnone) "Hauth". - - rewrite big_sepL_nil. iModIntro. rewrite map_empty_union. iFrame. - - rewrite big_sepL_cons. - iMod ("IH" $! M (l +â‚— 1) with "[] Hauth") as "[Helems Hauth]". - { iPureIntro. intros i Hi. rewrite shift_loc_assoc. replace (1 + i)%Z with (Z.of_nat (S i)) by lia. apply Hnone. - simpl; lia. - } - iMod (ghost_map_insert (t, l +â‚— 0%nat) sc with "Hauth") as "[Hauth Helem]". - { rewrite lookup_union_None; split. - - apply array_tag_map_lookup_None'. intros i Hi. destruct l; intros [= ?]. lia. - - apply Hnone. simpl; lia. - } - iModIntro. iFrame "Helem". rewrite shift_loc_0_nat. simpl. rewrite insert_union_l. iFrame "Hauth". - iApply (big_sepL_mono with "Helems"). intros i sc'' Hs. cbn. rewrite shift_loc_assoc. - replace (Z.of_nat $ S i) with (1 + i)%Z by lia. done. -Qed. - -Lemma ghost_map_array_tag_delete `{!bor_stateGS Σ} (γh : gname) (M : gmap (tag * block) (gmap Z scalar)) (v : list scalar) (t : tag) (l : loc) : - ghost_map_auth γh 1 M -∗ - ([∗ list] i ↦ sc ∈ v, ghost_map_elem γh (t, l +â‚— i) (DfracOwn 1) sc) ==∗ - ghost_map_auth γh 1 (M ∖ array_tag_map l t v). -Proof. - iIntros "Hauth Helems". - iApply (ghost_map_delete_big (array_tag_map l t v) with "Hauth [Helems]"). - iInduction v as [ | sc v] "IH" forall (l); first done. - simpl. iApply big_sepM_insert. - { destruct (_ !! _) eqn:Heq; last done. - specialize (array_tag_map_lookup2 (l +â‚— 1) t v t l ltac:(eauto)) as [_ (i & _ & Hl)]. - destruct l. injection Hl. lia. - } - rewrite shift_loc_0_nat. iDestruct "Helems" as "[$ Helems]". - iApply "IH". iApply (big_sepL_mono with "Helems"). - iIntros (i sc' Hi). simpl. - rewrite shift_loc_assoc. replace (Z.of_nat (S i)) with (1 + i) by lia; done. -Qed. - -Lemma ghost_map_array_tag_tk `{!bor_stateGS Σ} (γh : gname) (v : list scalar) (t : tag) (l : loc) tk : - ([∗ list] i ↦ sc ∈ v, ghost_map_elem γh (t, l +â‚— i) (DfracOwn 1) sc) ==∗ - ([∗ list] i ↦ sc ∈ v, ghost_map_elem γh (t, l +â‚— i) (tk_to_frac tk) sc). -Proof. - destruct tk; cbn; [ | by eauto ..]. - iInduction v as [| sc v] "IH" forall (l); first by eauto. - rewrite !big_sepL_cons. iIntros "[Hh Hr]". - iMod (ghost_map_elem_persist with "Hh") as "$". - iMod ("IH" $! (l +â‚— 1) with "[Hr]") as "Hr". - - iApply (big_sepL_mono with "Hr"). intros i sc' Hs. simpl. rewrite shift_loc_assoc. - by replace (Z.of_nat (S i)) with (1 + i) by lia. - - iModIntro. - iApply (big_sepL_mono with "Hr"). intros i sc' Hs. simpl. rewrite shift_loc_assoc. - by replace (Z.of_nat (S i)) with (1 + i) by lia. -Qed. -*) - Section val_rel. Context `{bor_stateGS Σ}. (** Value relation *) @@ -1601,7 +1258,7 @@ Section val_rel. (* through [state_rel]: * the stacks are the same, * the allocation size is the same, - * and the locations are related (i.e.: public) TODO: previously, scalars could be untagged. this no longer works. + * and the locations are related (i.e.: public) *) ⌜l1 = l2⌠∗ ⌜p1 = p2⌠∗ p1 $$ tk_pub | ScCallId c, ScCallId c' => ⌜c = c'⌠∗ pub_cid c @@ -1799,8 +1456,8 @@ Section val_rel. rewrite /value_rel. iApply (big_sepL2_app with "Hv1 Hv2"). Qed. - Definition will_read_in_simulation v_src v_tgt l_rd t : iProp Σ := - value_rel v_tgt v_src ∨ (⌜length v_src = length v_tgt⌠∗ ispoison (replicate (length v_tgt) ScPoison) l_rd t (length v_tgt)). + Definition will_read_in_simulation v_src v_tgt (l_rd : loc) (t : tag) : iProp Σ := + value_rel v_tgt v_src(* ∨ (⌜length v_src = length v_tgt⌠∗ ispoison (replicate (length v_tgt) ScPoison) l_rd t (length v_tgt))*). End val_rel. diff --git a/theories/tree_borrows/notation.v b/theories/tree_borrows/notation.v index f46cea9598ebaca799011c55d43ae693632ed32a..d3bb1ec740cb20e421bdc10945651a5e10a48cc9 100755 --- a/theories/tree_borrows/notation.v +++ b/theories/tree_borrows/notation.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From iris.prelude Require Import prelude options. From simuliris.tree_borrows Require Export lang_base. From iris.prelude Require Import options. @@ -89,8 +85,6 @@ Notation "'let:' x := e1 'in' e2" := (Let x%binder e1%E e2%E) Notation "e1 ;; e2" := (let: <> := e1 in e2)%R (at level 100, e2 at level 200, format "e1 ;; e2") : result_scope. -(*Notation "fun: xl , e" := (FunV xl%binder e%E)*) - (*(at level 102, xl at level 1, e at level 200).*) Ltac solve_closed := match goal with diff --git a/theories/tree_borrows/read_read_reorder/README.md b/theories/tree_borrows/read_read_reorder/README.md new file mode 100644 index 0000000000000000000000000000000000000000..39f1b8bea5fe519815c2e760c3e3a1e4bc261511 --- /dev/null +++ b/theories/tree_borrows/read_read_reorder/README.md @@ -0,0 +1,32 @@ +# Tree Borrows -- Read-read reorderings + +Example 18 focuses on the reordering of adjacent reads. +We claim that Tree Borrows allows reordering of any two adjacent read accesses. +The correctness of this optimization is trivial w.r.t. the state of the heap, +but not so much w.r.t. the state of the trees of borrows. +In fact this optimization is incorrect in Stacked Borrows! + +Our general framework is not at the moment capable of proving these optimizations because +they require one of +- absence of concurrency, or +- ability to reason about data races. +The latter has been demonstrated to be *possible* in simuliris (see `theories/simulang`), +but combining this with Tree Borrows is outside of our current scope. +Instead we opt for the former: this subdirectory has only sequential semantics, +no concurrency. + +The main theorem for this proof is `read_reorder` in `read_reorder.v`, +which states that the two example programs given that differ in the ordering +of two reads are equivalent according to the notion defined in `equivalence_def.v`. +In addition the intermediate lemmas in `low_level.v` should give confidence +that this reordering is indeed a more general property of the model and not +merely applicable to only this simple example. + +## Files + +In addition to the regular definitions of TB that are in the parent directory, +this proof is subdivided into + * `equivalence_def.v`: definition of a simple notion of program equivalence for a sequential setting. + * `low_level.v`: lemmas against the operational semantics. + * `read_reorder.v`: actual proof of equivalence between two programs in which adjacent reads have been swapped. (Example 18) + diff --git a/theories/tree_borrows/read_read_reorder/equivalence_def.v b/theories/tree_borrows/read_read_reorder/equivalence_def.v new file mode 100644 index 0000000000000000000000000000000000000000..4c3260d936355956bcc6214517418092325d9579 --- /dev/null +++ b/theories/tree_borrows/read_read_reorder/equivalence_def.v @@ -0,0 +1,36 @@ +From iris.prelude Require Import prelude options. +From stdpp Require Export gmap. +From simuliris.tree_borrows Require Import defs lang_base lang notation bor_semantics tree tactics class_instances. +From simuliris.tree_borrows.read_read_reorder Require Import low_level. +From iris.prelude Require Import options. + +(* [nsteps ... n] says that one can transition from one state to the other in exactly [n] +primitive steps. *) +(* This is similar to stdpp's [nsteps], except that this one computes more nicely for fixed [n]. *) +Fixpoint nsteps P (e : expr) σ e'' σ'' n : Prop := match n with + 0 => e = e'' ∧ σ = σ'' +| S n => ∃ e' σ', prim_step P e σ e' σ' nil ∧ nsteps P e' σ' e'' σ'' n end. + +(* This says that after n steps, any state reachable in from e_1 in σ must be reachable from e_2 in σ. + This is just a helper definition used for [eventually_equal]; on its own it is not very meaningful. *) +Definition identical_states_after P e1 e2 σ n := + ∀ e' σ', nsteps P e1 σ e' σ' n → nsteps P e2 σ e' σ' n. + +(* This says that the program will not terminate within a number of steps. + It can, in that time, only make progress or have UB *) +Inductive no_termination_within P : expr → state → nat → Prop := + | no_steps_left e σ : no_termination_within P e σ 0 + | no_termination_now e σ n : + to_result e = None → + (∀ e' σ', prim_step P e σ e' σ' nil → no_termination_within P e' σ' n) → + no_termination_within P e σ (S n). + +(* Two programs are eventually equal if there exists an n such that they + both do not terminate with n steps, + and after n steps, they are equal. *) +Definition eventually_equal P e1 e2 := + ∃ n, ∀ σ, state_wf σ → + no_termination_within P e1 σ n ∧ + no_termination_within P e2 σ n ∧ + identical_states_after P e1 e2 σ n ∧ + identical_states_after P e2 e1 σ n. diff --git a/theories/tree_borrows/read_read_reorder/low_level.v b/theories/tree_borrows/read_read_reorder/low_level.v new file mode 100644 index 0000000000000000000000000000000000000000..3406e20301ab63bff80a75169a209ab45975414c --- /dev/null +++ b/theories/tree_borrows/read_read_reorder/low_level.v @@ -0,0 +1,892 @@ +(** This file proves some simple reorderings directly against the operational semantics + in sequential code. + + For example we prove here the fact that in any context, two adjacent read + accesses can be swapped and the resulting state is identical to the initial state. + Because these proofs use a different definition of bor_step and do not involve + parallelism, the lemmas established here are *definitely not useful* for the rest + of the project. + + Results proven here: + * any pair of adjacent reads can be swapped to obtain an identical final state. + *) +From iris.prelude Require Import prelude options. +From stdpp Require Export gmap. +From simuliris.tree_borrows Require Import lang_base notation bor_semantics tree tree_lemmas bor_lemmas steps_preserve defs. +From iris.prelude Require Import options. + +Definition commutes {X} + (fn1 fn2 : X -> option X) + := forall x0 x1 x2, + fn1 x0 = Some x1 -> + fn2 x1 = Some x2 -> + exists x1', ( + fn2 x0 = Some x1' + /\ fn1 x1' = Some x2 + ). + +Definition commutes_option {X} + (fn1 fn2 : option X -> option X) + := forall x0 x1 x2, + fn1 x0 = Some x1 -> + fn2 (Some x1) = Some x2 -> + exists x1', ( + fn2 x0 = Some x1' + /\ fn1 (Some x1') = Some x2 + ). + +Definition persistent_if {X} (P : X -> Prop) + (fn1 fn2 : X -> option X) + := forall x x1 x2, + P x -> + fn1 x = Some x1 -> + fn2 x = Some x2 -> + exists x', fn2 x1 = Some x'. + +Definition persistent_if_option {X} (P : option X -> Prop) + (fn1 fn2 : option X -> option X) + := forall x x1 x2, + P x -> + fn1 x = Some x1 -> + fn2 x = Some x2 -> + exists x', fn2 (Some x1) = Some x'. + +Lemma apply_access_perm_read_commutes + {rel1 rel2 prot} + : commutes + (apply_access_perm AccessRead rel1 prot) + (apply_access_perm AccessRead rel2 prot). +Proof. + move=> p0 p1 p2 Step01 Step12. + unfold apply_access_perm in *. + all: destruct p0 as [[] [[]| | | | ]]. + all: destruct prot; simpl in *. + all: destruct rel1; simpl in *. + all: try (inversion Step01; done). + all: injection Step01; intros; subst. + all: simpl. + all: destruct rel2; simpl in *. + all: try (inversion Step12; done). + all: injection Step12; intros; subst; simpl. + all: try (eexists; split; [reflexivity|]); simpl. + all: reflexivity. +Qed. + +Lemma apply_access_perm_read_persistent + {rel1 rel2 prot} + : persistent_if lazy_perm_wf + (apply_access_perm AccessRead rel1 prot) + (apply_access_perm AccessRead rel2 prot). +Proof. + move=> p0 p1 p2 wf Step01 Step12. + unfold apply_access_perm in *. + all: destruct p0 as [[] [[]| | | | ]]. + all: destruct prot; simpl in *. + all: destruct rel1; simpl in *. + all: try (inversion Step01; done). + all: injection Step01; intros; subst. + all: simpl. + all: destruct rel2; simpl in *. + all: try (inversion Step12; done). + all: injection Step12; intros; subst; simpl. + all: try (eexists; reflexivity). + (* Only the non-wf cases remain *) + - rewrite /lazy_perm_wf in wf; simpl in *. exfalso. + specialize (wf ltac:(auto)). discriminate. + - rewrite /lazy_perm_wf in wf; simpl in *. exfalso. + specialize (wf ltac:(auto)). discriminate. +Qed. + +Lemma mem_apply_loc_insert_ne + {X} {fn : option X -> option X} {z mem mem' z0} + (NE : ~z = z0) + (Success : mem_apply_loc fn z mem = Some mem') + v0 + : mem_apply_loc fn z (<[z0:=v0]>mem) = Some (<[z0:=v0]>mem'). +Proof. + unfold mem_apply_loc in Success |- *; simpl in *. + rewrite lookup_insert_ne; [|auto]. + destruct (option_bind_success_step _ _ _ Success) as [v [fnv mem'_spec]]. + injection mem'_spec; intros; subst. + rewrite fnv; simpl. + f_equal. + rewrite insert_commute; auto. +Qed. + +Lemma mem_apply_range'_insert_outside + {X} {fn : option X -> option X} {z sz mem mem' z0} + (OUT : ~range'_contains (z, sz) z0) + (Success : mem_apply_locs fn z sz mem = Some mem') + v0 + : mem_apply_locs fn z sz (<[z0:=v0]>mem) = Some (<[z0:=v0]>mem'). +Proof. + unfold mem_apply_range' in *; simpl in *. + generalize dependent z. + generalize dependent mem. + generalize dependent mem'. + induction sz as [|sz IHsz]; move=> mem' mem z OUT Success. + - injection Success; intros; subst. + reflexivity. + - destruct (proj1 (bind_Some _ _ _) Success) as [mem'' [SuccessStep SuccessRest]]. + simpl. + erewrite mem_apply_loc_insert_ne; [| |eassumption]. + 2: { unfold range'_contains in OUT |- *; simpl in *; lia. } + simpl. + apply IHsz. + + unfold range'_contains in OUT |- *; simpl in *; lia. + + exact SuccessRest. +Qed. + +Lemma mem_apply_range'_success_condition + {X} {fn : option X -> option X} {range mem} + (ALL_SOME : forall z, range'_contains range z -> is_Some (fn (mem !! z))) + : exists mem', mem_apply_range' fn range mem = Some mem'. +Proof. + unfold mem_apply_range'. + destruct range as [z sz]; simpl. + generalize dependent z. + induction sz as [|sz IHsz]; move=> z ALL_SOME. + - eexists. simpl. reflexivity. + - destruct (IHsz (z + 1)%Z + ltac:(intros mem' H; apply ALL_SOME; unfold range'_contains; unfold range'_contains in H; simpl; simpl in H; lia)) + as [sub' Specsub']. + destruct (ALL_SOME z ltac:(unfold range'_contains; simpl; lia)) as [fnz Specfnz]. + eexists (<[z:=fnz]>sub'); simpl. + unfold mem_apply_loc. + rewrite Specfnz; simpl. + erewrite mem_apply_range'_insert_outside; [reflexivity| |assumption]. + unfold range'_contains; simpl; lia. +Qed. + +Lemma mem_apply_range'_success_specification + {X} {fn : option X -> option X} {range mem mem'} + (ALL_SOME : forall z, range'_contains range z -> exists x', fn (mem !! z) = Some x' /\ mem' !! z = Some x') + (REST_SAME : forall z, ~range'_contains range z -> mem !! z = mem' !! z) + : mem_apply_range' fn range mem = Some mem'. +Proof. + assert (forall z, range'_contains range z -> is_Some (fn (mem !! z))) as ALL_SOME_weaker. { + intros z R; destruct (ALL_SOME z R) as [?[??]]; auto. + } + destruct (mem_apply_range'_success_condition ALL_SOME_weaker) as [mem'' Spec'']. + rewrite Spec''; f_equal; apply map_eq. + intro z. + pose proof (mem_apply_range'_spec _ _ z _ _ Spec'') as Spec. + destruct (decide (range'_contains range z)) as [R|nR]. + - destruct Spec as [v[vSpec fnvSpec]]. + destruct (ALL_SOME z R) as [v' [fnv'Spec v'Spec]]. + rewrite v'Spec. + rewrite vSpec. + rewrite <- fnv'Spec. + rewrite <- fnvSpec. + reflexivity. + - rewrite <- (REST_SAME z nR). + assumption. +Qed. + +Lemma range_foreach_commutes + {X} + range1 range2 + (fn1 fn2 : option X -> option X) + (FnCommutes : commutes_option fn1 fn2) + : commutes + (mem_apply_range' fn1 range1) + (mem_apply_range' fn2 range2). +Proof. + intros mem0 mem1 mem2 Success01 Success12. + assert (forall z, range'_contains range2 z -> exists x1', fn2 (mem0 !! z) = Some x1') as fn2mem0. { + intros z R2. + pose proof (mem_apply_range'_spec _ _ z _ _ Success01) as Spec01. + pose proof (mem_apply_range'_spec _ _ z _ _ Success12) as Spec12. + destruct (decide (range'_contains range1 z)). + - destruct Spec01 as [fn1z0 [z1Spec fn1z0Spec]]. + rewrite decide_True in Spec12; [|assumption]. + destruct Spec12 as [fn2z1 [z2Spec fn2z1Spec]]. + rewrite z1Spec in fn2z1Spec. + destruct (FnCommutes _ _ _ fn1z0Spec fn2z1Spec) as [x1' [fn2z0Spec fn1x1'Spec]]. + exists x1'; assumption. + - rewrite decide_True in Spec12; [|assumption]. + destruct Spec12 as [x2 [x2Spec fn2x1Spec]]. + exists x2; rewrite <- Spec01; assumption. + } + destruct (mem_apply_range'_success_condition fn2mem0) as [mem1' Success01']. + exists mem1'. + split; [assumption|]. + apply mem_apply_range'_success_specification. + - intros z R1. + pose proof (mem_apply_range'_spec _ _ z _ _ Success01) as Spec01. + pose proof (mem_apply_range'_spec _ _ z _ _ Success12) as Spec12. + pose proof (mem_apply_range'_spec _ _ z _ _ Success01') as Spec01'. + destruct (decide (range'_contains range2 z)). + + rewrite decide_True in Spec01; [|assumption]. + destruct Spec01 as [fn1z0 [z1Spec fn1z0Spec]]. + destruct Spec12 as [fn2z1 [z2Spec fn2z1Spec]]. + destruct Spec01' as [fn2z0 [z1'Spec fn2z0Spec]]. + rewrite z1Spec in fn2z1Spec. + destruct (FnCommutes _ _ _ fn1z0Spec fn2z1Spec) as [x2' [fn2z0'Spec fn1x2'Spec]]. + rewrite z1'Spec. + rewrite <- fn2z0Spec. + exists fn2z1. + split; [|assumption]. + destruct (FnCommutes _ _ _ fn1z0Spec fn2z1Spec) as [x1' [fn2z0Spec' fn1x1'Spec]]. + rewrite fn2z0Spec'. + rewrite fn1x1'Spec. + reflexivity. + + rewrite decide_True in Spec01; [|assumption]. + destruct Spec01 as [fn1z0 [z1Spec fn1z0Spec]]. + rewrite Spec01'. + rewrite Spec12. + exists fn1z0; split; assumption. + - intros z nR1. + pose proof (mem_apply_range'_spec _ _ z _ _ Success01) as Spec01. + pose proof (mem_apply_range'_spec _ _ z _ _ Success01') as Spec01'. + pose proof (mem_apply_range'_spec _ _ z _ _ Success12) as Spec12. + destruct (decide (range'_contains range2 z)). + + rewrite decide_False in Spec01; [|assumption]. + destruct Spec01' as [fn2z0 [z1'Spec fn2z0Spec]]. + destruct Spec12 as [fn2z1 [z2Spec fn2z1Spec]]. + rewrite z1'Spec. + rewrite <- fn2z0Spec. + rewrite <- Spec01. + rewrite fn2z1Spec. + rewrite z2Spec. + reflexivity. + + rewrite decide_False in Spec01; [|assumption]. + rewrite Spec01'. + rewrite <- Spec01. + rewrite Spec12. + reflexivity. +Qed. + +Definition if_some_then {X} (P : X -> Prop) o := + match o with + | None => True + | Some x => P x + end. + +Lemma range_foreach_persistent + {X} + P + range1 range2 + (fn1 fn2 : option X -> option X) + (FnCommutes : persistent_if_option (if_some_then P) fn1 fn2) + : persistent_if (fun m => forall i, if_some_then P (m !! i)) + (mem_apply_range' fn1 range1) + (mem_apply_range' fn2 range2). +Proof. + intros mem0 mem1 mem2 Wf Success01 Success12. + assert (forall z, range'_contains range2 z -> exists x', fn2 (mem1 !! z) = Some x') as fn2mem1. { + intros z R2. + pose proof (mem_apply_range'_spec _ _ z _ _ Success01) as Spec01. + pose proof (mem_apply_range'_spec _ _ z _ _ Success12) as Spec12. + destruct (decide (range'_contains range1 z)). + - destruct Spec01 as [fn1z0 [z1Spec fn1z0Spec]]. + rewrite decide_True in Spec12; [|assumption]. + pose proof (Wf z) as wfz. + destruct Spec12 as [fn2z1 [z2Spec fn2z1Spec]]. + destruct (FnCommutes _ _ _ wfz fn1z0Spec fn2z1Spec) as [x1' fn2z0Spec]. + exists x1'; rewrite z1Spec; assumption. + - rewrite decide_True in Spec12; [|assumption]. + destruct Spec12 as [x2 [x2Spec fn2x1Spec]]. + exists x2; rewrite Spec01; assumption. + } + destruct (mem_apply_range'_success_condition fn2mem1) as [mem1' Success01']. + exists mem1'. assumption. +Qed. + +Lemma commutes_option_build + {X} {dflt : X} {fn1 fn2} + (Commutes : commutes fn1 fn2) + : commutes_option + (fun ox => fn1 (default dflt ox)) + (fun ox => fn2 (default dflt ox)). +Proof. + intros x0 x1 x2 Step01 Step12. + destruct (Commutes (default dflt x0) _ _ Step01 Step12) as [?[??]]. + eexists; eauto. +Qed. + +Lemma persistent_if_option_build + {X} {dflt : X} P {fn1 fn2} + (Commutes : persistent_if P fn1 fn2) + (Base : P dflt) + : persistent_if_option (if_some_then P) + (fun ox => fn1 (default dflt ox)) + (fun ox => fn2 (default dflt ox)). +Proof. + intros x0 x1 x2 Pre Step01 Step12. + destruct x0; simpl in *. + - destruct (Commutes _ _ _ Pre Step01 Step12) as [? ?]. + eexists; eassumption. + - destruct (Commutes _ _ _ Base Step01 Step12) as [? ?]. + eexists; eassumption. +Qed. + +Lemma permissions_foreach_commutes + range1 range2 + (fn1 fn2 : lazy_permission -> option lazy_permission) + dflt + (FnCommutes : commutes fn1 fn2) + : commutes + (permissions_apply_range' dflt range1 fn1) + (permissions_apply_range' dflt range2 fn2). +Proof. + apply range_foreach_commutes. + apply commutes_option_build. + assumption. +Qed. + +Lemma permissions_foreach_persistent + P + range1 range2 + (fn1 fn2 : lazy_permission -> option lazy_permission) + dflt + (FnCommutes : persistent_if P fn1 fn2) + (Base : P dflt) + : persistent_if (fun m => forall i, if_some_then P (m !! i)) + (permissions_apply_range' dflt range1 fn1) + (permissions_apply_range' dflt range2 fn2). +Proof. + apply range_foreach_persistent. + apply persistent_if_option_build. + - assumption. + - assumption. +Qed. + +Lemma item_apply_access_read_commutes + {cids rel1 rel2 range1 fn1 fn2 range2} + (FnCommutes : forall isprot, + commutes + (fn1 rel1 isprot) + (fn2 rel2 isprot)) + : commutes + (item_apply_access fn1 cids rel1 range1) + (item_apply_access fn2 cids rel2 range2). +Proof. + intros it0 it1 it2 Step01 Step12. + option step in Step01 as ?:S1. + option step in Step12 as ?:S2. + injection Step01; destruct it1 as [??? iperm1]; intro H; injection H; intros; subst; simpl in *; clear Step01; clear H. + injection Step12; destruct it2 as [??? iperm2]; intro H; injection H; intros; subst; simpl in *; clear Step12; clear H. + destruct (permissions_foreach_commutes + range1 range2 + (fn1 _ _) (fn2 _ _) + {| initialized:=PermLazy; perm:=initp it0 |} + (FnCommutes _) + (*(apply_access_perm_read_commutes (rel1:=rel1) (rel2:=rel2) (prot:=bool_decide (protector_is_active (iprot it0) cids)))*) + (iperm it0) iperm1 iperm2 + S1 S2) as [perms' [Pre Post]]. + unfold item_apply_access. + rewrite Pre; simpl. + eexists; split; [reflexivity|]. + simpl. rewrite Post; simpl. + reflexivity. +Qed. + +Lemma item_apply_access_read_persistent + {cids rel1 rel2 range1 fn1 fn2 range2} + (FnCommutes : forall isprot, + persistent_if lazy_perm_wf + (fn1 rel1 isprot) + (fn2 rel2 isprot)) + : persistent_if (fun it => exists nxtc nxtp, item_wf it nxtc nxtp) + (item_apply_access fn1 cids rel1 range1) + (item_apply_access fn2 cids rel2 range2). +Proof. + intros it0 it1 it2 Pre Step01 Step12. + option step in Step01 as ?:S1. + option step in Step12 as ?:S2. + injection Step01; destruct it1 as [??? iperm1]; intro H; injection H; intros; subst; simpl in *; clear Step01; clear H. + injection Step12; destruct it2 as [??? iperm2]; intro H; injection H; intros; subst; simpl in *; clear Step12; clear H. + destruct Pre as [nxtc [nxtp itWf]]. + assert (lazy_perm_wf {| initialized:=PermLazy; perm := initp it0 |}) as LazyWf. { + rewrite /lazy_perm_wf /=. + intro Absurd. + exfalso. eapply itWf.(item_default_perm_valid it0 _ _). assumption. + } + assert (forall i, if_some_then lazy_perm_wf (iperm it0 !! i)) as InitWf. { + pose proof (itWf.(item_perms_valid it0 _ _)) as AllWf. + intro i. + destruct (iperm it0 !! i) as [perm|] eqn:permSpec. + 2: simpl; done. + simpl. + apply (map_Forall_lookup_1 _ _ i perm AllWf permSpec). + } + destruct (permissions_foreach_persistent + lazy_perm_wf + range1 range2 + (fn1 _ _) (fn2 _ _) + {| initialized:=PermLazy; perm:=initp it0 |} + (FnCommutes _) + LazyWf + (iperm it0) iperm1 iperm2 + InitWf + S1 S2) as [perms' Res]. + unfold item_apply_access; simpl. + eexists. rewrite Res; simpl. + reflexivity. +Qed. + +Lemma apply_access_success_condition + {fn cids access_tag range tr} + (ALL_SOME : every_node + (fun it => is_Some (item_apply_access fn cids (rel_dec tr access_tag (itag it)) range it)) tr) + : exists tr', tree_apply_access fn cids access_tag range tr = Some tr'. +Proof. + assert (every_node is_Some (map_nodes (fun it => item_apply_access fn cids (rel_dec tr access_tag (itag it)) range it) tr)) as AllSomeMap by (rewrite every_node_map; assumption). + destruct (proj2 (join_success_condition _) AllSomeMap). + eexists; eassumption. +Qed. + +Lemma join_map_commutes + {fn1 fn2 : call_id_set -> rel_pos -> Z * nat -> item -> option item} {cids access_tag1 access_tag2 range1 range2} + (Fn1PreservesTag : forall it it' cids rel range, fn1 cids rel range it = Some it' -> itag it = itag it') + (Fn2PreservesTag : forall it it' cids rel range, fn2 cids rel range it = Some it' -> itag it = itag it') + (Commutes : forall rel1 rel2, commutes + (fn1 cids rel1 range1) + (fn2 cids rel2 range2)) + (* We need the two [rel_dec] to refer to the same tree otherwise the proof would be much more difficult *) + : forall (tr0:tree item), + commutes + (fun tr => join_nodes (map_nodes (fun it => fn1 cids (rel_dec tr0 access_tag1 it.(itag)) range1 it) tr)) + (fun tr => join_nodes (map_nodes (fun it => fn2 cids (rel_dec tr0 access_tag2 it.(itag)) range2 it) tr)). +Proof. + intros tr tr0. + induction tr0 as [|data0 left0 IHleft right0 IHright]; intros tr1 tr2 Step01 Step12. + - simpl in Step01; injection Step01; intros; subst. + simpl in Step12; injection Step12; intros; subst. + exists tree.empty; simpl; tauto. + - option step in Step01 as data1:Data01. + option step in Step01 as left1:Left01. + option step in Step01 as right1:Right01. + injection Step01; intros; subst. + option step in Step12 as data2:Data12. + option step in Step12 as left2:Left12. + option step in Step12 as right2:Right12. + injection Step12; intros; subst. + destruct (Commutes _ _ data0 data1 data2 Data01 Data12) as [data1' [Data01' Data1'2]]. + destruct (IHleft left1 left2 Left01 Left12) as [left1' [Left01' Left1'2]]. + destruct (IHright right1 right2 Right01 Right12) as [right1' [Right01' Right1'2]]. + exists (branch data1' left1' right1'). + simpl in *. + assert (itag data0 = itag data1) as Tg01 by (eapply Fn1PreservesTag; eassumption). + assert (itag data0 = itag data1') as Tg01' by (eapply Fn2PreservesTag; eassumption). + rewrite Tg01; rewrite Data01'; simpl. + rewrite Left01'; simpl. + rewrite Right01'; simpl. + rewrite <- Tg01'; rewrite Data1'2; simpl. + rewrite Left1'2; simpl. + rewrite Right1'2; simpl. + tauto. +Qed. + +Lemma join_map_persistent + {fn1 fn2 : call_id_set -> rel_pos -> Z * nat -> item -> option item} {cids access_tag1 access_tag2 range1 range2} + (Fn1PreservesTag : forall it it' cids rel range, fn1 cids rel range it = Some it' -> itag it = itag it') + (Fn2PreservesTag : forall it it' cids rel range, fn2 cids rel range it = Some it' -> itag it = itag it') + (Commutes : forall rel1 rel2, persistent_if (fun it => exists nxtp nxtc, item_wf it nxtp nxtc) + (fn1 cids rel1 range1) + (fn2 cids rel2 range2)) + (* We need the two [rel_dec] to refer to the same tree otherwise the proof would be much more difficult *) + : forall (tr0:tree item), + persistent_if (fun tr => exists nxtp nxtc, tree_items_compat_nexts tr nxtp nxtc) + (fun tr => join_nodes (map_nodes (fun it => fn1 cids (rel_dec tr0 access_tag1 it.(itag)) range1 it) tr)) + (fun tr => join_nodes (map_nodes (fun it => fn2 cids (rel_dec tr0 access_tag2 it.(itag)) range2 it) tr)). +Proof. + intros tr tr0 tr1 tr2 Pre. + destruct Pre as [nxtp [nxtc AllWf]]. + revert tr1 tr2. + induction tr0 as [|data0 left0 IHleft right0 IHright]; intros tr1 tr2 Step01 Step12. + - simpl in Step01; injection Step01; intros; subst. + simpl in Step12; injection Step12; intros; subst. + exists tree.empty; simpl; tauto. + - option step in Step01 as data1:Data01. + option step in Step01 as left1:Left01. + option step in Step01 as right1:Right01. + injection Step01; intros; subst. + option step in Step12 as data2:Data12. + option step in Step12 as left2:Left12. + option step in Step12 as right2:Right12. + injection Step12; intros; subst. + inversion AllWf as [RootWf [LeftWf RightWf]]. + destruct (Commutes _ _ data0 data1 data2 ltac:(eexists; eexists; exact RootWf) Data01 Data12) as [data1' Res]. + destruct (IHleft LeftWf left1 left2 Left01 Left12) as [left1' LeftRes]. + destruct (IHright RightWf right1 right2 Right01 Right12) as [right1' RightRes]. + exists (branch data1' left1' right1'). + simpl in *. + assert (itag data0 = itag data1) as Tg01 by (eapply Fn1PreservesTag; eassumption). + rewrite -Tg01; rewrite Res; simpl. + rewrite LeftRes. + rewrite RightRes. + simpl. + reflexivity. +Qed. + +Lemma tree_apply_access_only_cares_about_rel + {tr} {fn : call_id_set -> rel_pos -> Z * nat -> item -> option item} {cids access_tag range} + {tr1 tr2} + (Agree : forall tg tg', ParentChildIn tg tg' tr1 <-> ParentChildIn tg tg' tr2) + (RAgree : forall tg tg', ImmediateParentChildIn tg tg' tr1 <-> ImmediateParentChildIn tg tg' tr2) + : join_nodes (map_nodes (fun it => fn cids (rel_dec tr1 access_tag it.(itag)) range it) tr) + = join_nodes (map_nodes (fun it => fn cids (rel_dec tr2 access_tag it.(itag)) range it) tr). +Proof. + induction tr as [|data sibling IHsibling child IHchild]; [simpl; reflexivity|]. + simpl. + rewrite IHsibling; clear IHsibling. + rewrite IHchild; clear IHchild. + unfold rel_dec. + f_equal. f_equal. + destruct (decide (ParentChildIn _ _ _)) as [R1|R1]. + all: destruct (decide (ParentChildIn _ _ _)) as [R1'|R1']. + all: destruct (decide (ParentChildIn _ _ _)) as [R2|R2]. + all: destruct (decide (ParentChildIn _ _ _)) as [R2'|R2']. + all: try reflexivity. + all: rewrite <- Agree in R2'; auto; try contradiction. + all: rewrite <- Agree in R2; auto; try contradiction. + all: erewrite decide_ext; last apply RAgree. + all: done. +Qed. + +Lemma tree_apply_access_commutes + {fn1 fn2 cids access_tag1 access_tag2 range1 range2} + (Commutes : forall rel1 rel2, commutes + (item_apply_access fn1 cids rel1 range1) + (item_apply_access fn2 cids rel2 range2)) + : commutes + (fun tr => tree_apply_access fn1 cids access_tag1 range1 tr) + (fun tr => tree_apply_access fn2 cids access_tag2 range2 tr). +Proof. + unfold tree_apply_access. + intros tr0 tr1 tr2 Step01 Step12. + assert (forall (it it' : item) (cids : call_id_set) (rel : rel_pos) (range : Z * nat), + item_apply_access fn1 cids rel range it = Some it' + → itag it = itag it') as Fn1PreservesTag. { + intros. eapply item_apply_access_preserves_metadata. eassumption. + } + assert (forall (it it' : item) (cids : call_id_set) (rel : rel_pos) (range : Z * nat), + item_apply_access fn2 cids rel range it = Some it' + → itag it = itag it') as Fn2PreservesTag. { + intros. eapply item_apply_access_preserves_metadata. eassumption. + } + + erewrite tree_apply_access_only_cares_about_rel in Step01. + 1: erewrite tree_apply_access_only_cares_about_rel in Step12. + 1: edestruct (join_map_commutes + Fn1PreservesTag + Fn2PreservesTag + Commutes _ tr0 tr1 tr2 Step01 Step12) as [tr1' [Step01' Step1'2]]. 1: exists tr1'; split; [exact Step01'|]. + 1: erewrite tree_apply_access_only_cares_about_rel in Step1'2. + 1: exact Step1'2. + all: intros tg tg'. + - eapply join_map_eqv_rel; [|eassumption]. intros it it' H. eapply Fn2PreservesTag. exact H. + - eapply join_map_eqv_imm_rel; [|eassumption]. intros it it' H. eapply Fn2PreservesTag. exact H. + - symmetry. eapply join_map_eqv_rel; [|eassumption]. intros it it' H. eapply Fn1PreservesTag. exact H. + - symmetry. eapply join_map_eqv_imm_rel; [|eassumption]. intros it it' H. eapply Fn1PreservesTag. exact H. + - tauto. + - tauto. +Qed. + +Lemma tree_apply_access_persistent + {fn1 fn2 cids access_tag1 access_tag2 range1 range2} + (Commutes : forall rel1 rel2, persistent_if (fun it => exists nxtp nxtc, item_wf it nxtp nxtc) + (item_apply_access fn1 cids rel1 range1) + (item_apply_access fn2 cids rel2 range2)) + : persistent_if (fun tr => exists nxtp nxtc, tree_items_compat_nexts tr nxtp nxtc) + (fun tr => tree_apply_access fn1 cids access_tag1 range1 tr) + (fun tr => tree_apply_access fn2 cids access_tag2 range2 tr). +Proof. + unfold tree_apply_access. + intros tr0 tr1 tr2 Pre Step01 Step12. + assert (forall (it it' : item) (cids : call_id_set) (rel : rel_pos) (range : Z * nat), + item_apply_access fn1 cids rel range it = Some it' + → itag it = itag it') as Fn1PreservesTag. { + intros. eapply item_apply_access_preserves_metadata. eassumption. + } + assert (forall (it it' : item) (cids : call_id_set) (rel : rel_pos) (range : Z * nat), + item_apply_access fn2 cids rel range it = Some it' + → itag it = itag it') as Fn2PreservesTag. { + intros. eapply item_apply_access_preserves_metadata. eassumption. + } + + erewrite tree_apply_access_only_cares_about_rel in Step01. + 1: erewrite tree_apply_access_only_cares_about_rel in Step12. + 1: edestruct (join_map_persistent + Fn1PreservesTag + Fn2PreservesTag + Commutes _ tr0 tr1 tr2 Pre Step01 Step12) as [tr1' Res]. + 1: exists tr1'. + 1: exact Res. + all: intros tg tg'. + - eapply join_map_eqv_rel; [|eassumption]. intros it it' H. eapply Fn1PreservesTag. exact H. + - eapply join_map_eqv_imm_rel; [|eassumption]. intros it it' H. eapply Fn1PreservesTag. exact H. + - eapply join_map_eqv_rel; [|eassumption]. intros it it' H. eapply Fn1PreservesTag. exact H. + - eapply join_map_eqv_imm_rel; [|eassumption]. intros it it' H. eapply Fn1PreservesTag. exact H. +Qed. + + +Lemma memory_access_read_commutes + {cids access_tag1 access_tag2 range1 range2} + : commutes + (memory_access AccessRead cids access_tag1 range1) + (memory_access AccessRead cids access_tag2 range2). +Proof. + unfold memory_access. + apply tree_apply_access_commutes; intros. + apply item_apply_access_read_commutes; intros. + apply apply_access_perm_read_commutes. +Qed. + +Lemma memory_access_read_persistent + {cids access_tag1 access_tag2 range1 range2} + : persistent_if (fun tr => exists nxtp nxtc, tree_items_compat_nexts tr nxtp nxtc) + (memory_access AccessRead cids access_tag1 range1) + (memory_access AccessRead cids access_tag2 range2). +Proof. + unfold memory_access. + apply tree_apply_access_persistent; intros. + apply item_apply_access_read_persistent; intros. + apply apply_access_perm_read_persistent. +Qed. + +Lemma apply_within_trees_commutes + {fn1 fn2 alloc1 alloc2} + (Commutes : commutes fn1 fn2) + : commutes + (apply_within_trees fn1 alloc1) + (apply_within_trees fn2 alloc2) + . +Proof. + intros trs0 trs1 trs2 App0 App1. + (* Move forward *) + rewrite bind_Some in App0. destruct App0 as [tr0 [tr0Spec App0]]. + rewrite bind_Some in App0. destruct App0 as [tr1 [tr1Spec App0]]. + injection App0; intros; clear App0; subst. + rewrite bind_Some in App1. destruct App1 as [tr1b [tr1bSpec App1]]. + rewrite bind_Some in App1. destruct App1 as [tr2 [tr2Spec App1]]. + injection App1; intros; clear App1; subst. + (* Now we do the interesting case distinction *) + destruct (decide (alloc1 = alloc2)). + - (* Same allocation *) + subst. + assert (tr1 = tr1b). { + rewrite lookup_insert in tr1bSpec. injection tr1bSpec. tauto. + } + subst. + destruct (Commutes _ _ _ tr1Spec tr2Spec) as [tr1' [tr1'SpecA tr1'SpecB]]. + exists (<[alloc2:=tr1']> trs0). + split. + + rewrite bind_Some. exists tr0. split; first done. + rewrite tr1'SpecA; simpl; done. + + rewrite bind_Some. exists tr1'. + split. + * apply lookup_insert. + * rewrite tr1'SpecB; simpl. + f_equal. + do 2 rewrite insert_insert. + reflexivity. + - (* Not the same allocation *) + exists (<[alloc2:=tr2]> trs0). + split. + + rewrite bind_Some. exists tr1b. + split. + * rewrite <- tr1bSpec. rewrite lookup_insert_ne; done. + * rewrite tr2Spec; done. + + rewrite bind_Some. exists tr0. + split. + * rewrite <- tr0Spec. rewrite lookup_insert_ne; done. + * rewrite tr1Spec; simpl. + f_equal. apply insert_commute. done. +Qed. + +Lemma apply_within_trees_persistent + {fn1 fn2 alloc1 alloc2} + (Commutes : persistent_if (fun tr => exists nxtp nxtc, tree_items_compat_nexts tr nxtp nxtc) fn1 fn2) + : persistent_if (fun trs => exists nxtp nxtc, trees_compat_nexts trs nxtp nxtc) + (apply_within_trees fn1 alloc1) + (apply_within_trees fn2 alloc2) + . +Proof. + intros trs0 trs1 trs2 Pre App0 App1. + destruct Pre as [nxtp [nxtc AllWf]]. + (* Move forward *) + rewrite bind_Some in App0. destruct App0 as [tr0 [tr0Spec App0]]. + rewrite bind_Some in App0. destruct App0 as [tr1 [tr1Spec App0]]. + injection App0; intros; clear App0; subst. + rewrite bind_Some in App1. destruct App1 as [tr1b [tr1bSpec App1]]. + rewrite bind_Some in App1. destruct App1 as [tr2 [tr2Spec App1]]. + injection App1; intros; clear App1; subst. + pose proof (AllWf alloc1 tr0 tr0Spec) as tr0Wf. + (* Now we do the interesting case distinction *) + destruct (decide (alloc1 = alloc2)). + - (* Same allocation *) + subst. + assert (tr0 = tr1b). { + rewrite tr0Spec in tr1bSpec. + injection tr1bSpec. tauto. + } + subst. + destruct (Commutes _ _ _ ltac:(eexists; eexists; apply tr0Wf) tr1Spec tr2Spec) as [tr1' Res]. + eexists. + rewrite bind_Some. eexists. + split. + + rewrite lookup_insert; reflexivity. + + rewrite Res; simpl; reflexivity. + - (* Not the same allocation *) + eexists. + + rewrite bind_Some. exists tr1b. + split. + * rewrite <- tr1bSpec. rewrite lookup_insert_ne; done. + * rewrite tr2Spec; simpl. done. +Qed. + +Lemma apply_read_within_trees_commutes + {cids tg1 range1 alloc1 tg2 range2 alloc2} + : commutes + (apply_within_trees (memory_access AccessRead cids tg1 range1) alloc1) + (apply_within_trees (memory_access AccessRead cids tg2 range2) alloc2) + . +Proof. + apply apply_within_trees_commutes. + apply memory_access_read_commutes. +Qed. + +Lemma apply_read_within_trees_persistent + {cids tg1 range1 alloc1 tg2 range2 alloc2} + : persistent_if (fun trs => exists nxtp nxtc, trees_compat_nexts trs nxtp nxtc) + (apply_within_trees (memory_access AccessRead cids tg1 range1) alloc1) + (apply_within_trees (memory_access AccessRead cids tg2 range2) alloc2) + . +Proof. + apply apply_within_trees_persistent. + apply memory_access_read_persistent. +Qed. + +Lemma read_failure_preserved + {cids tg1 range1 alloc1 tg2 range2 alloc2 trs0 trs1} + (Wf : exists nxtp nxtc, trees_compat_nexts trs0 nxtp nxtc) + (Read1 : apply_within_trees (memory_access AccessRead cids tg1 range1) alloc1 trs0 = Some trs1) + : + apply_within_trees (memory_access AccessRead cids tg2 range2) alloc2 trs0 = None + <-> + apply_within_trees (memory_access AccessRead cids tg2 range2) alloc2 trs1 = None + . +Proof. + split. + + intro Fail0. + destruct (apply_within_trees (memory_access AccessRead cids tg2 range2) alloc2 trs1) eqn:Acc1. + 2: reflexivity. + exfalso. + destruct (apply_read_within_trees_commutes _ _ _ Read1 Acc1) as [x1' [Read' _]]. + rewrite Read' in Fail0. discriminate. + + intro Fail1. + destruct (apply_within_trees (memory_access AccessRead cids tg2 range2) alloc2 trs0) eqn:Acc0. + 2: reflexivity. + destruct (apply_read_within_trees_persistent _ _ _ Wf Read1 Acc0) as [x' Read']. + rewrite Read' in Fail1. + discriminate. +Qed. + +Lemma apply_read_within_trees_same_tags + {tg trs trs' cids tg' range blk blk'} + (ACC : apply_within_trees (memory_access AccessRead cids tg' range) blk' trs = Some trs') + : trees_contain tg trs blk <-> trees_contain tg trs' blk. +Proof. + rewrite bind_Some in ACC. destruct ACC as [tr [trSpec ACC]]. + rewrite bind_Some in ACC. destruct ACC as [tr' [tr'Spec ACC]]. + injection ACC; intros; clear ACC; subst. + rewrite /trees_contain /trees_at_block. + destruct (decide (blk = blk')). + + subst. rewrite lookup_insert. rewrite trSpec. + eapply access_preserves_tags. + apply tr'Spec. + + rewrite lookup_insert_ne; last done. + reflexivity. +Qed. + +Lemma CopyEvt_commutes + { trs0 cids0 nxtp0 nxtc0 + alloc1 tg1 range1 val1 + trs1 cids1 nxtp1 nxtc1 + alloc2 tg2 range2 val2 + trs2 cids2 nxtp2 nxtc2 + } + (Step1 : + bor_step + trs0 cids0 nxtp0 nxtc0 + (CopyEvt alloc1 tg1 range1 val1) + trs1 cids1 nxtp1 nxtc1) + (Step2 : + bor_step + trs1 cids1 nxtp1 nxtc1 + (CopyEvt alloc2 tg2 range2 val2) + trs2 cids2 nxtp2 nxtc2) + : exists trs1' cids1' nxtp1' nxtc1', + bor_step + trs0 cids0 nxtp0 nxtc0 + (CopyEvt alloc2 tg2 range2 val2) + trs1' cids1' nxtp1' nxtc1' + /\ + bor_step + trs1' cids1' nxtp1' nxtc1' + (CopyEvt alloc1 tg1 range1 val1) + trs2 cids2 nxtp2 nxtc2 + . +Proof. + inversion Step1 as [|????? EXISTS1 ACC1 SZ1| | | | | | | |]. + - subst. + inversion Step2 as [|????? EXISTS2 ACC2 SZ2| | | | | | | |]. + + subst. + destruct (apply_read_within_trees_commutes _ _ _ ACC1 ACC2) as [trs1' [ACC2' ACC1']]. + exists trs1'. exists cids2. exists nxtp2. exists nxtc2. + split. + * econstructor; eauto. + rewrite apply_read_within_trees_same_tags; last exact ACC2'. + rewrite apply_read_within_trees_same_tags; last exact ACC1'. + rewrite- apply_read_within_trees_same_tags; last exact ACC2. + assumption. + * econstructor; eauto. + rewrite apply_read_within_trees_same_tags; last exact ACC1'. + rewrite- apply_read_within_trees_same_tags; last exact ACC2. + rewrite- apply_read_within_trees_same_tags; last exact ACC1. + assumption. + + subst. + repeat eexists. + 1: econstructor 3; auto. + econstructor; eauto. + - subst. + inversion Step2 as [|????? EXISTS2 ACC2 SZ2| | | | | | | |]. + + subst. + repeat eexists. + 1: econstructor; eauto. + econstructor 3; eauto. + + subst. + repeat eexists. + all: econstructor 3; eauto. +Qed. + +Lemma bor_steps_CopyEvt_commutes + { trs0 cids0 nxtp0 nxtc0 + alloc1 tg1 range1 val1 + alloc2 tg2 range2 val2 + trs2 cids2 nxtp2 nxtc2 + } + (Steps : bor_steps + trs0 cids0 nxtp0 nxtc0 + [CopyEvt alloc1 tg1 range1 val1; CopyEvt alloc2 tg2 range2 val2] + trs2 cids2 nxtp2 nxtc2) + : bor_steps + trs0 cids0 nxtp0 nxtc0 + [CopyEvt alloc2 tg2 range2 val2; CopyEvt alloc1 tg1 range1 val1] + trs2 cids2 nxtp2 nxtc2 + . +Proof. + inversion Steps as [|?????????? HEAD1 REST1]. + inversion REST1 as [|?????????? HEAD2 REST2]. + inversion REST2. + subst. + destruct (CopyEvt_commutes HEAD1 HEAD2) as [?[?[?[?[HEAD2' HEAD1']]]]]. + econstructor; last econstructor; last constructor. + + apply HEAD2'. + + apply HEAD1'. +Qed. + + diff --git a/theories/tree_borrows/read_read_reorder/read_reorder.v b/theories/tree_borrows/read_read_reorder/read_reorder.v new file mode 100644 index 0000000000000000000000000000000000000000..7c46d17b470650ca95dfcdb2288804b783634e16 --- /dev/null +++ b/theories/tree_borrows/read_read_reorder/read_reorder.v @@ -0,0 +1,233 @@ +From iris.prelude Require Import prelude options. +From stdpp Require Export gmap. +From simuliris.tree_borrows Require Import defs lang_base lang notation bor_semantics tree tree_lemmas bor_lemmas steps_preserve tactics class_instances. +From simuliris.tree_borrows.read_read_reorder Require Import low_level equivalence_def. +From iris.prelude Require Import options. + +Definition source (x1 x2 : string) l1 tg1 sz1 l2 tg2 sz2 erest : expr := + let: x1 := Copy (Place l1 tg1 sz1) in + let: x2 := Copy (Place l2 tg2 sz2) in + erest. + +Definition target (x1 x2 : string) l1 tg1 sz1 l2 tg2 sz2 erest : expr := + let: x2 := Copy (Place l2 tg2 sz2) in + let: x1 := Copy (Place l1 tg1 sz1) in + erest. + + +Ltac solve_sub_redexes_are_values := + let K := fresh "K" in + let e' := fresh "e'" in + let Heq := fresh "Heq" in + let Hv := fresh "Hv" in + let IH := fresh "IH" in + let Ki := fresh "Ki" in + let Ki' := fresh "Ki'" in + intros K e' Heq Hv; + destruct K as [ | Ki K]; first (done); + exfalso; induction K as [ | Ki' K IH] in e', Ki, Hv, Heq |-*; + [destruct Ki; inversion Heq; subst; cbn in *; + try rewrite to_val_of_result in Hv; congruence + | eapply IH; first (by rewrite Heq); + rewrite language_to_val_eq; apply fill_item_no_result; + by rewrite -language_to_val_eq]. + +Lemma list_destruct_snoc {A} (l : list A) : + l = nil ∨ ∃ xt xh, l = xh ++ [xt]. +Proof. + rewrite -(rev_involutive l). + destruct (rev l) as [|xt xh]; first by left. + right. simpl. by repeat eexists. +Qed. + +Lemma prim_step_let_inv x e es e' P σ σ' tt : + prim_step P (let: x := e in es) σ e' σ' tt → + (∃ ev, language.to_val e = Some ev ∧ tt = nil ∧ σ' = σ ∧ e' = subst' x e es) ∨ + ∃ ei', language.to_val e = None ∧ prim_step P e σ ei' σ' tt ∧ e' = (let: x := ei' in es)%E. +Proof. + destruct (language.to_val e) as [ev|] eqn:Hev. + - intros H%prim_base_step. + 2: solve_sub_redexes_are_values. + inversion H as [x1 x2 x3 x4 EE| x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 EE]; simplify_eq. + 2: by inversion EE. + inversion EE; simplify_eq. left. eexists. done. + - intros (K&e1'&e2'&He1&He2&H)%prim_step_inv. + destruct (list_destruct_snoc K) as [->|(xt & xh & ->)]. + + simpl in *; simplify_eq. + inversion H as [x1 x2 x3 x4 EE| x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 EE]; simplify_eq. + 2: by inversion EE. + inversion EE; simplify_eq. + match goal with [HH : is_Some (to_result e) |- _ ] => + rewrite -language_to_val_eq Hev in HH; by destruct HH end. + + subst e'. rewrite /= fill_app in He1. + destruct xt; simplify_eq. + replace (Let x e es) with (fill [LetEctx x es] e) in He1; last done. + simplify_eq. right. eexists. + rewrite /= fill_app /=. + split; first done. + split; last done. + eapply fill_prim_step. eapply base_prim_step. done. +Qed. + +Lemma prim_step_copy_inv l tg sz P σ e' σ' tt : + prim_step P (Copy (Place l tg sz)) σ e' σ' tt → + (∃ v trs', e' = (#v)%E ∧ tt = nil ∧ read_mem l sz (shp σ) = Some v ∧ trees_contain tg (strs σ) l.1 ∧ apply_within_trees (memory_access AccessRead (scs σ) tg (l.2, sz)) l.1 (strs σ) = Some trs' ∧ sz ≠0 ∧ σ' = mkState (shp σ) trs' (scs σ) (snp σ) (snc σ)) +∨ (∃ v, e' = (#v)%E ∧ tt = nil ∧ read_mem l sz (shp σ) = Some v ∧ sz = 0 ∧ σ' = σ) +(*∨ (e' = (#(replicate sz ☠%S))%E ∧ tt = nil ∧ is_Some (read_mem l sz (shp σ)) ∧ trees_contain tg (strs σ) l.1 ∧ apply_within_trees (memory_access AccessRead (scs σ) tg (l.2, sz)) l.1 (strs σ) = None ∧ σ' = σ)*). +Proof. + intros H%prim_base_step. + 2: solve_sub_redexes_are_values. + inversion H as [x1 x2 x3 x4 EE| x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 ME IE]; simplify_eq. + 1: by inversion EE. + inversion ME; simplify_eq. + - inversion IE; simplify_eq. + + left. do 2 eexists. done. + + right. eexists. do 4 (split; first done). by destruct σ. +(* - simpl in *. + inversion IE; simplify_eq. right. right. + do 5 (split; first done). + by destruct σ. *) +Qed. + +Lemma subst_val_twice_exchange e x1 x2 v1 v2 : + x1 ≠x2 → + subst x1 (#v1)%E (subst' x2 (#v2)%E e) = subst x2 (#v2)%E (subst' x1 (#v1)%E e). +Proof. + intros Hne. + simpl. + refine ((fix IH (e:expr) {struct e} : subst x1 #v1 (subst x2 #v2 e) = subst x2 #v2 (subst x1 #v1 e) := _) e). + destruct e as [| | | | | | | | | | | | | | | | |? el| | ]; simpl; try (f_equal; by eapply IH). + - clear IH. rewrite !bool_decide_decide. do 2 destruct decide; simplify_eq; simpl. + + rewrite bool_decide_decide decide_True //. + + rewrite bool_decide_decide decide_True //. + + do 2 rewrite bool_decide_decide decide_False //. + - f_equal. 1: apply IH. f_equal. rewrite !bool_decide_decide. do 2 destruct decide; simplify_eq; simpl; done. + - f_equal. 1: eapply IH. + induction el as [|?? IHel]; first done. + + simpl. f_equal. 2: apply IHel. apply IH. +Qed. + +Lemma read_reorder_onesided x1 x2 l1 tg1 sz1 l2 tg2 sz2 erest P σ : + state_wf σ → + x1 ≠x2 → + identical_states_after P (source x1 x2 l1 tg1 sz1 l2 tg2 sz2 erest) (target x1 x2 l1 tg1 sz1 l2 tg2 sz2 erest) σ 4. +Proof. + destruct l1 as [blk1 off1], l2 as [blk2 off2]. + intros Hwf Hne. + intros e4 σ4 (e1' & σ1 & [(?&[=]&_)|(e1&_&[(v1&trs1&->&_&Hread1&Hcontain1&Happly1&Hne1&->)|(v1&->&_&Hrd1&->&->)]%prim_step_copy_inv&->)]%prim_step_let_inv & Hrst). + all: destruct Hrst as (e2 & σ2 & [(?&[= <-]&_&->&->)|(?&[=]&_)]%prim_step_let_inv & Hrst). + all: simpl in *|-. + all: destruct Hrst as (e3' & σ3 & [(?&[=]&_)|(e3&_&[(v3&trs3&->&_&Hread3&Hcontain3&Happly3&Hne2&->)|(v3&->&_&Hrd3&->&->)]%prim_step_copy_inv&->)]%prim_step_let_inv & Hrst). + all: simpl in *|-. + all: destruct Hrst as (e4' & σ4' & [(?&[= <-]&_&->&->)|(?&[=]&_)]%prim_step_let_inv & <- & <-). + all: rewrite /target. + all: rewrite bool_decide_decide decide_True; last congruence. + all: do 2 change (subst' (BNamed ?a) ?b ?c) with (subst a b c). + all: rewrite subst_val_twice_exchange //. + - (* read x1: succeed, read x2: succeed *) + odestruct CopyEvt_commutes as (y1&y2&y3&y4&HH1&HH2). + { econstructor. 1: eapply Hcontain1. 1: eapply Happly1. 1: done. } + { econstructor. 1: eapply Hcontain3. 1: eapply Happly3. 1: done. } + do 2 eexists. split. + { change (Let ?x2 ?a ?b) with (fill [LetEctx x2 b] a). + eapply fill_prim_step. eapply base_prim_step. + econstructor 2. 1: econstructor 3. 1: done. + eapply HH1. } + do 2 eexists. split. + { simpl. eapply base_prim_step. + econstructor 1. econstructor. 1: done. done. } + do 2 eexists. simpl. split. + { change (Let ?x2 ?a ?b) with (fill [LetEctx x2 b] a). + eapply fill_prim_step. eapply base_prim_step. + econstructor 2. 1: econstructor 3. 1: done. simpl. done. } + do 2 eexists. split. + { simpl. eapply base_prim_step. + econstructor 1. econstructor. 1: done. done. } + split; last done. rewrite bool_decide_decide decide_True //; congruence. + - (* read x1: succeed, read x2: zerosized *) + do 2 eexists. split. + { change (Let ?x2 ?a ?b) with (fill [LetEctx x2 b] a). + eapply fill_prim_step. eapply base_prim_step. + econstructor 2. 1: econstructor 3. 1: done. + econstructor; done. } + do 2 eexists. split. + { simpl. eapply base_prim_step. + econstructor 1. econstructor. 1: done. done. } + do 2 eexists. simpl. split. + { change (Let x1 ?a ?b) with (fill [LetEctx x1 b] a). + eapply fill_prim_step. eapply base_prim_step. + econstructor 2. 1: econstructor 3. 1: done. simpl. + econstructor; done. } + do 2 eexists. split. + { simpl. eapply base_prim_step. + econstructor 1. econstructor. 1: done. done. } + split; last done. rewrite bool_decide_decide decide_True //; congruence. + - (* read x1: zerosized, read x2: succeed *) + do 2 eexists. split. + { change (Let x2 ?a ?b) with (fill [LetEctx x2 b] a). + eapply fill_prim_step. eapply base_prim_step. + econstructor 2. 1: simpl; econstructor 3. 1: done. + econstructor; done. } + do 2 eexists. split. + { simpl. eapply base_prim_step. + econstructor 1. econstructor. 1: done. done. } + do 2 eexists. simpl. split. + { change (Let x1 ?a ?b) with (fill [LetEctx x1 b] a). + eapply fill_prim_step. eapply base_prim_step. + econstructor 2. 1: econstructor 3. 1: done. simpl. + econstructor; done. } + do 2 eexists. split. + { simpl. eapply base_prim_step. + econstructor 1. econstructor. 1: done. done. } + split; last done. rewrite bool_decide_decide decide_True //; congruence. + - (* read x1: zerosized, read x2: zerosized *) + do 2 eexists. simplify_eq. split. + { change (Let x2 ?a ?b) with (fill [LetEctx x2 b] a). + eapply fill_prim_step. eapply base_prim_step. + econstructor 2. 1: econstructor 3. 1: done. + econstructor; done. } + do 2 eexists. split. + { simpl. eapply base_prim_step. + econstructor 1. econstructor. 1: done. done. } + do 2 eexists. simpl. split. + { change (Let x1 ?a ?b) with (fill [LetEctx x1 b] a). + eapply fill_prim_step. eapply base_prim_step. + econstructor 2. 1: econstructor 3. 1: done. simpl. + econstructor; done. } + do 2 eexists. split. + { simpl. eapply base_prim_step. + econstructor 1. econstructor. 1: done. done. } + split; last by destruct σ. rewrite bool_decide_decide decide_True //; congruence. +Qed. + +Lemma read_example_no_termination x1 x2 l1 tg1 sz1 l2 tg2 sz2 erest P σ : + x1 ≠x2 → + no_termination_within P (source x1 x2 l1 tg1 sz1 l2 tg2 sz2 erest) σ 4. +Proof. + intros Hne. + econstructor; first done. + intros e' σ' [(?&[=]&_)|(e1&_&[(v1&trs1&->&_&Hread1&Hcontain1&Happly1&Hne1&->)|(v1&->&_&Hrd1&->&->)]%prim_step_copy_inv&->)]%prim_step_let_inv. + all: econstructor; first done. + all: intros e' σ' [(?&[= <-]&_&->&->)|(?&[=]&_)]%prim_step_let_inv. + all: econstructor; first done. + all: intros e' σ' [(?&[=]&_)|(e3&_&[(v3&trs3&->&_&Hread3&Hcontain3&Happly3&Hne2&->)|(v3&->&_&Hrd3&->&->)]%prim_step_copy_inv&->)]%prim_step_let_inv. + all: econstructor; first done. + all: intros e' σ' [(?&[= <-]&_&->&->)|(?&[=]&_)]%prim_step_let_inv. + all: econstructor. +Qed. + +Theorem read_reorder x1 x2 l1 tg1 sz1 l2 tg2 sz2 erest P : + x1 ≠x2 → + eventually_equal P (source x1 x2 l1 tg1 sz1 l2 tg2 sz2 erest) (target x1 x2 l1 tg1 sz1 l2 tg2 sz2 erest). +Proof. + intros H1. + exists 4. + intros σ Hσ. + split; first by eapply read_example_no_termination. + split; first by eapply read_example_no_termination. + split; eapply read_reorder_onesided; done. +Qed. + +(* +Print Assumptions read_reorder. +*) \ No newline at end of file diff --git a/theories/tree_borrows/refl.v b/theories/tree_borrows/refl.v index ba7acb4eec4e1024373cffdee195139c3c52ee6e..e9509dea0bf7fc6a41c857a7bc3f59d29cf6c046 100755 --- a/theories/tree_borrows/refl.v +++ b/theories/tree_borrows/refl.v @@ -277,7 +277,6 @@ Section log_rel. iDestruct (value_rel_length with "Hv1") as %EqL. iDestruct (value_rel_lookup with "Hv1") as (sc_t sc_s Eqt Eqs) "Hsc". { rewrite EqL. eapply Nat2Z.inj_lt, lookup_lt_Some; eauto. } - (* TODO: I don't know how to fix sim_pures to do this. *) target_proj; [done|]. source_proj; [done|]. solve_rrel_refl. Qed. @@ -373,8 +372,6 @@ Section log_rel. iIntros (t) "Hv". sim_val. eauto. Qed. - (* TODO: this can be useful elsewhere. It's here because I'm relying on the - several useful tactics defined here. *) Local Lemma sim_case Ï€ e_t e_s el_t el_s Ψ : e_t ⪯{Ï€} e_s {{ rrel }} -∗ ([∗ list] e_t';e_s' ∈ el_t;el_s, e_t' ⪯{Ï€} e_s' [{ Ψ }]) -∗ @@ -389,7 +386,6 @@ Section log_rel. rename select (_ !! _ = Some _) into Hls. assert (∃ e_t', el_t !! Z.to_nat i = Some e_t') as [? Hlt]. { apply lookup_lt_is_Some_2. apply lookup_lt_Some in Hls. by rewrite EqL. } - (* TODO sim_pures? *) target_case; [done|]. source_case; [done|]. sim_pures. iApply (big_sepL2_lookup _ _ _ _ _ _ Hlt Hls with "Hle"). Qed. diff --git a/theories/tree_borrows/step_laws/steps_local.v b/theories/tree_borrows/step_laws/steps_local.v index b5f8c61987663cd9f6637567fba867a2404f87e6..512e4adb2c4d5439e7912a19beca28f00aef80f9 100644 --- a/theories/tree_borrows/step_laws/steps_local.v +++ b/theories/tree_borrows/step_laws/steps_local.v @@ -50,19 +50,19 @@ Proof. { iPureIntro. do 3 eexists. eapply copy_base_step'. 1: done. 2: exact READ_MEM. 2: exact TREES_NOCHANGE. rewrite /trees_contain /trees_at_block /= Hit. subst t. cbv. tauto. } iIntros (??? Hstep). - eapply head_copy_inv in Hstep as (->&[((HNone&_&_&_)&_)|(trs'&v'&->&->&Hreadv'&[(_&Happly&Hnon)|(Hzero&->&->)])]). - 1: rewrite /= TREES_NOCHANGE // in HNone. + eapply head_copy_inv in Hstep as (->&trs'&v'&->&->&Hreadv'&[(_&Happly&Hnon)|(Hzero&->&->)]). - iModIntro. iSplitR; first done. assert (v_rd = v') as -> by congruence. iSplitR "Htag Ht Hsim"; last first. 1: iApply ("Hsim" with "Ht Htag"). - iFrame. simpl in Happly. assert (trs' = strs σ_t) as -> by congruence. + iFrame "HP_t HP_s". + simpl in Happly. assert (trs' = strs σ_t) as -> by congruence. iExists _, _, _, _. destruct σ_t. iApply "Hbor". - iModIntro. iSplitR; first done. assert (v_rd = []) as -> by by destruct v_rd. iSplitR "Htag Ht Hsim"; last first. 1: iApply ("Hsim" with "Ht Htag"). - iFrame. + iFrame "HP_t HP_s". iExists _, _, _, _. destruct σ_t. iApply "Hbor". Qed. @@ -96,7 +96,7 @@ Proof. iModIntro. iSplitR "Htag Ht Hsim"; last first. 1: iApply ("Hsim" with "Ht Htag"). - iFrame. destruct σ_s; simpl. + iFrame "HP_t HP_s". destruct σ_s; simpl. iExists _, _, _, _. iApply "Hbor". Qed. @@ -134,7 +134,8 @@ Proof. iIntros (??? Hstep). pose proof Hstep as Hstep2. eapply head_write_inv in Hstep2 as (trs'&->&->&->&_&Hiinv&[(Hcont&Happly&Hlen)|(Hlen&->)]); last first. { iModIntro. iSplit; first done. - assert (v_wr = nil) as -> by by destruct v_wr. iFrame. + assert (v_wr = nil) as -> by by destruct v_wr. + iFrame "HP_t HP_s". iSplitL "Hbor". 1: repeat iExists _; destruct σ_t; done. eapply write_range_to_list_is_Some in Hwrite as (x&Hx&_). simpl in Hx. subst v_t'. iApply ("Hsim" with "Ht Htag"). } diff --git a/theories/tree_borrows/step_laws/steps_prot.v b/theories/tree_borrows/step_laws/steps_prot.v index f83ce82d265e96dd57f1bc839e59cf716c202760..1b9df53a76b362a1d4a96bee2f1db18e25157a8d 100644 --- a/theories/tree_borrows/step_laws/steps_prot.v +++ b/theories/tree_borrows/step_laws/steps_prot.v @@ -54,8 +54,8 @@ Proof. iSplit. { iPureIntro. do 3 eexists. eapply copy_base_step'. 1: done. 2: exact READ_MEM. 2: exact Htrs'. done. } iIntros (??? Hstep). pose proof Hstep as Hstep2. - eapply head_copy_inv in Hstep2 as (->&[((HNone&_&_&_)&_)|(trs''&v'&->&->&Hreadv'&[(_&Htrs''&Hnon)|(Hzero&->&->)])]). - 1: rewrite /= Htrs' // in HNone. 2: done. + eapply head_copy_inv in Hstep2 as (->&trs''&v'&->&->&Hreadv'&[(_&Htrs''&Hnon)|(Hzero&->&->)]). + 2: done. assert (trs'' = trs') as ->. { rewrite /memory_access Htrs' in Htrs''. congruence. } assert (v_rd = v') as -> by congruence. diff --git a/theories/tree_borrows/step_laws/steps_read_write_simple.v b/theories/tree_borrows/step_laws/steps_read_write_simple.v index 458bff3772d72c0160f0f5240b513445aa942785..d839a85f9e7f00af6757310d2bffae3716eaaf81 100644 --- a/theories/tree_borrows/step_laws/steps_read_write_simple.v +++ b/theories/tree_borrows/step_laws/steps_read_write_simple.v @@ -33,9 +33,7 @@ Proof. { iPureIntro. do 3 eexists. econstructor 2. 1: eapply CopyBS. 1: done. eapply ZeroCopyIS. done. } iIntros (e_t' efs_t σ_t' Hstep). - eapply head_copy_inv in Hstep as (->&[((HNone&->&->&HH1)&Hintree)|(trs'&v'&->&->&Hread&[(_&_&HH)|(_&->&->)])]). - - iModIntro. iSplit; first done. simpl. iFrame "Hsim". - iFrame. + eapply head_copy_inv in Hstep as (->&trs'&v'&->&->&Hread&[(_&_&HH)|(_&->&->)]). - lia. - iModIntro. iSplit; first done. simpl. iFrame "HP_s HP_t Hsim". do 4 iExists _. destruct σ_t. done. Qed. @@ -69,7 +67,7 @@ Proof. eapply head_write_inv in Hstep as (trs'&->&->&->&_&_&[(_&_&?)|(_&->)]). - lia. - iModIntro. iSplit; first done. simpl. iFrame "Hsim". - iFrame. destruct σ_t. by repeat iExists _. + iFrame "HP_t HP_s". destruct σ_t. by repeat iExists _. Qed. Lemma source_write_zero l t v Ï€ Ψ : @@ -102,9 +100,9 @@ Proof. destruct Hsafe as [Hpool Hsafe]. iPoseProof (bor_interp_get_pure with "Hbor") as "%Hp". destruct Hp as (Hstrs_eq & Hsnp_eq & Hsnc_eq & Hscs_eq & Hwf_s & Hwf_t & Hdom_eq). - specialize (pool_safe_implies Hsafe Hpool) as [(vr_s&Hreadmem&Hcontain_s&(trs_s'&Htrss)&_)|[(_&_&[]%Hne)|(Hcontain_s&Hnotrees&Hisval)]]; + specialize (pool_safe_implies Hsafe Hpool) as [(vr_s&Hreadmem&Hcontain_s&(trs_s'&Htrss)&_)|(_&_&[]%Hne)]; pose proof Hcontain_s as Hcontain_t; rewrite trees_equal_same_tags in Hcontain_t; try done; last first. - { (* We get poison *) +(* { (* We get poison *) assert (apply_within_trees (memory_access AccessRead (scs σ_s) bor_s (l_s.2, sz)) l_s.1 (strs σ_t) = None) as Hnotrees_t. { destruct apply_within_trees eqn:HSome in |-*; try done. eapply mk_is_Some, trees_equal_allows_more_access in HSome as (x&Hx); first by erewrite Hnotrees in Hx. @@ -120,7 +118,7 @@ Proof. { iPureIntro. subst e_t'. destruct σ_s, l_s. simpl. do 2 econstructor; by eauto. } simpl. iFrame. iSplit; last done. subst e_t'. iApply "Hsim". iApply big_sepL_sepL2_diag. iApply big_sepL_forall. by iIntros (k v (->&_)%lookup_replicate_1). - } + } *) edestruct trees_equal_allows_more_access as (trs_t'&Htrst). 1: done. 1: eapply Hwf_s. 1,2,3: rewrite ?Hscs_eq; eapply Hwf_t. 1: done. 1: done. 1: by eapply mk_is_Some. opose proof (trees_equal_preserved_by_access _ _ _ _ _ _ _ Hstrs_eq _ Htrss Htrst) as Hstrs_eq'. @@ -131,7 +129,7 @@ Proof. { iPureIntro. do 3 eexists. eapply copy_base_step'. 1-3: done. rewrite -Hscs_eq. done. } (* we keep the base_step hypotheses to use the [base_step_wf] lemma below *) iIntros (e_t' efs_t σ_t') "%Hhead_t". - specialize (head_copy_inv _ _ _ _ _ _ _ _ Hhead_t) as (->&[((Hnotree&->&Hpoison&Hheapsome)&Hcontains_t)|(tr'&vr_t'&->&Hσ_t'&H3&[(Hcontains_t&H4&_)|([]%Hne&_&_)])]); first congruence. + specialize (head_copy_inv _ _ _ _ _ _ _ _ Hhead_t) as (->&tr'&vr_t'&->&Hσ_t'&H3&[(Hcontains_t&H4&_)|([]%Hne&_&_)]). assert (vr_t' = vr_t) as -> by congruence. assert (tr' = trs_t') as -> by congruence. clear H3 H4. diff --git a/theories/tree_borrows/step_laws/steps_retag.v b/theories/tree_borrows/step_laws/steps_retag.v index 5ae3fb2147a46a3701a4bfa7911a41cfa0dd608b..2b2626cb4d19121a63ad6155c21b5551b42eb50b 100644 --- a/theories/tree_borrows/step_laws/steps_retag.v +++ b/theories/tree_borrows/step_laws/steps_retag.v @@ -21,8 +21,6 @@ Implicit Types l : loc. Implicit Types f : fname. - - (** ** Retags *) Lemma tree_access_succeeds_heap_value σ b ak tg blk off sz : diff --git a/theories/tree_borrows/step_laws/steps_source_only.v b/theories/tree_borrows/step_laws/steps_source_only.v index c8f1ee6db2b25898a8abf53d54a1ab8f50a9ce18..b1c08a4e44195bf797e6d24ddb656cd18f4c5cd8 100644 --- a/theories/tree_borrows/step_laws/steps_source_only.v +++ b/theories/tree_borrows/step_laws/steps_source_only.v @@ -31,7 +31,7 @@ Lemma source_copy_any v_t v_rd sz l_hl l_rd t Ï€ Ψ tk : l_hl.1 = l_rd.1 → t $$ tk -∗ l_hl ↦s∗[tk]{t} v_t -∗ - (∀ v_res, l_hl ↦s∗[tk]{t} v_t -∗ t $$ tk -∗ (⌜v_res = v_rd⌠∨ ispoison v_res l_rd t sz) -∗ source_red #v_res Ï€ Ψ)%E -∗ + (∀ v_res, l_hl ↦s∗[tk]{t} v_t -∗ t $$ tk -∗ (⌜v_res = v_rdâŒ) -∗ source_red #v_res Ï€ Ψ)%E -∗ source_red (Copy (Place l_rd t sz)) Ï€ Ψ. Proof. iIntros (Hnz Hread Hsameblk) "Htag Hs Hsim". eapply read_range_length in Hread as HH. subst sz. @@ -40,9 +40,9 @@ Proof. destruct Hp as (Hstrs_eq & Hsnp_eq & Hsnc_eq & Hscs_eq & Hwf_s & Hwf_t & Hdom_eq). iModIntro. iDestruct "Hbor" as "(%M_call & %M_tag & %M_t & %M_s & Hbor)". eapply pool_safe_implies in Ht_s as Hfoo. 2: done. - destruct Hfoo as [(v_rd'&Hv_rd&Hcont&Hreadsome&_)|[(v_nil&Hread_nil&Hiszero)|(Hcont&Happly_none&Hmemsome)]]; last first. + destruct Hfoo as [(v_rd'&Hv_rd&Hcont&Hreadsome&_)|(v_nil&Hread_nil&Hiszero)]. 2: lia. - { (* poison *) +(* { (* poison *) pose proof Happly_none as Hn2. rewrite /apply_within_trees in Hn2. rewrite /trees_contain /trees_at_block in Hcont. @@ -88,7 +88,7 @@ Proof. 1: simpl; lia. simpl. assert ((l_rd +â‚— Z.to_nat (l - l_rd.2) = (l_rd.1, l))) as ->. 2: done. rewrite /shift_loc /=. simpl. f_equal. lia. } 1: iSplitR "Hsim"; last by iApply "Hsim". - do 4 iExists _; destruct σ_s; iFrame. iFrame "Hsrel". done. } + do 4 iExists _; destruct σ_s; iFrame. iFrame "Hsrel". done. } *) iPoseProof (bor_interp_readN_source_after_accesss with "Hbor Hs Htag") as "(%it&%tr&%Hit&%Htr&%Hown)". 1: exact Hread. 1: done. 1: done. 1: done. 1: exact Hreadsome. opose proof* (read_range_list_to_heaplet_read_memory_strict) as READ_MEM. 1: exact Hread. 1: done. @@ -122,7 +122,7 @@ Proof. iModIntro. iSplitR "Hs Htag Hsim". - 2: { iApply ("Hsim" with "Hs Htag"). iLeft. by iPureIntro. } + 2: { iApply ("Hsim" with "Hs Htag"). by iPureIntro. } iFrame "HP_t HP_s". iExists M_call, M_tag, M_t, M_s. iFrame "Hc Htag_auth Htag_t_auth Htag_s_auth". iSplitL "Htainted"; last iSplitL "Hpub_cid". 3: iSplit; last iSplit; last (iPureIntro; split_and!). @@ -145,7 +145,7 @@ Proof. - eapply (base_step_wf P_s). 2: exact Hwf_s. eapply copy_base_step'. 1: done. 2: exact READ_MEM. 2: exact Htrs'. done. - done. Qed. - +(* Lemma source_copy_poison v_t v_rd sz l_hl l_rd t Ï€ Ψ tk v_read_earlier : sz ≠0%nat → (* if it is 0, it will not be poison *) read_range l_rd.2 sz (list_to_heaplet v_t l_hl.2) = Some v_rd → @@ -183,7 +183,7 @@ Proof. opose proof (disabled_tag_no_access _ false _ AccessRead _ (l_rd.2 + i) (l_rd.2, length v_rd) _ HH _) as HNone. 1: by eapply Hwf_s. 1: split; simpl in *; lia. rewrite /memory_access HNone in Hreadsome. simpl in Hreadsome. by destruct Hreadsome. -Qed. +Qed. *) Lemma source_copy_in_simulation v_t v_rd v_tgt sz l_hl l_rd t Ï€ Ψ tk : @@ -198,12 +198,13 @@ Lemma source_copy_in_simulation v_t v_rd v_tgt sz l_hl l_rd t Ï€ Ψ tk : Proof. iIntros (Hsz Hrr Hhl). eapply read_range_length in Hrr as Hszlen. - iIntros "#[Hrel|Hpoison] Htk Hhl Hsim". + iIntros "#Hrel Htk Hhl Hsim". + rewrite /will_read_in_simulation. - iPoseProof (value_rel_length with "Hrel") as "%Hlen". iApply (source_copy_any with "Htk Hhl [Hsim]"). 1-3: done. - iIntros (v_res) "Hhl Htk [->|#(%i&(%Hp1&%Hp2)&Hpoison2)]"; + iIntros (v_res) "Hhl Htk ->"; iApply ("Hsim" with "Hhl Htk"). - + done. + + done. (* + rewrite Hp2. iApply big_sepL2_forall. iSplit. 1: iPureIntro; rewrite length_replicate; lia. iIntros (k sc1 sc2 _ (->&HH2)%lookup_replicate_1). iApply sc_rel_source_poison. - subst sz. iDestruct "Hpoison" as "(%Hlen&Hpoison)". @@ -212,7 +213,7 @@ Proof. iIntros (v_res) "Hhl Htk #(%i&(%Hp1&%Hp2)&Hpoison2)". iApply ("Hsim" with "Hhl Htk"). rewrite Hp2. iApply big_sepL2_forall. iSplit. 1: iPureIntro; rewrite length_replicate; lia. - iIntros (k sc1 sc2 _ (->&HH2)%lookup_replicate_1). iApply sc_rel_source_poison. + iIntros (k sc1 sc2 _ (->&HH2)%lookup_replicate_1). iApply sc_rel_source_poison. *) Qed. diff --git a/theories/tree_borrows/step_laws/steps_unique.v b/theories/tree_borrows/step_laws/steps_unique.v index 3f067ec989d8b903d10a0add74c94c0e61ce7041..03cede0bdaed34d5d9a0235f5685500bdb5ed927 100644 --- a/theories/tree_borrows/step_laws/steps_unique.v +++ b/theories/tree_borrows/step_laws/steps_unique.v @@ -34,7 +34,7 @@ Lemma sim_copy v_t v_s v_rd_t v_rd_s sz l_hl l_rd t Ï€ tk Φ : t $$ tk -∗ l_hl ↦s∗[tk]{t} v_s -∗ l_hl ↦t∗[tk]{t} v_t -∗ - (∀ v_res_s v_res_t, l_hl ↦s∗[tk]{t} v_s -∗ l_hl ↦t∗[tk]{t} v_t -∗ t $$ tk -∗ (⌜v_res_s = v_rd_s ∧ v_res_t = v_rd_t⌠∨ ispoison v_res_s l_rd t sz ∗ ispoison v_res_t l_rd t sz) -∗ #v_res_t ⪯{Ï€} #v_res_s [{ Φ }])%E -∗ + (∀ v_res_s v_res_t, l_hl ↦s∗[tk]{t} v_s -∗ l_hl ↦t∗[tk]{t} v_t -∗ t $$ tk -∗ (⌜v_res_s = v_rd_s ∧ v_res_t = v_rd_t⌠(*∨ ispoison v_res_s l_rd t sz ∗ ispoison v_res_t l_rd t sz*)) -∗ #v_res_t ⪯{Ï€} #v_res_s [{ Φ }])%E -∗ (Copy (Place l_rd t sz)) ⪯{Ï€} (Copy (Place l_rd t sz)) [{ Φ }]. Proof. iIntros (Hsz Hreadt Hreads Hl) "Htk Hs Ht Hsim". @@ -43,9 +43,9 @@ Proof. destruct Hsafe as [Hpool Hsafe]. iPoseProof (bor_interp_get_pure with "Hbor") as "%Hp". destruct Hp as (Hstrs_eq & Hsnp_eq & Hsnc_eq & Hscs_eq & Hwf_s & Hwf_t & Hdom_eq). - specialize (pool_safe_implies Hsafe Hpool) as [(vr_s&Hreadmem&Hcontain_s&(trs_s'&Htrss)&_)|[(_&_&[]%Hsz)|(Hcontain_s&Hnotrees&Hisval)]]; + specialize (pool_safe_implies Hsafe Hpool) as [(vr_s&Hreadmem&Hcontain_s&(trs_s'&Htrss)&_)|(_&_&[]%Hsz)]; pose proof Hcontain_s as Hcontain_t; rewrite trees_equal_same_tags in Hcontain_t; try done; last first. - { (* We get poison *) +(* { (* We get poison *) assert (apply_within_trees (memory_access AccessRead (scs σ_s) t (l_rd.2, sz)) l_rd.1 (strs σ_t) = None) as Hnotrees_t. { destruct apply_within_trees eqn:HSome in |-*; try done. eapply mk_is_Some, trees_equal_allows_more_access in HSome as (x&Hx); first by erewrite Hnotrees in Hx. @@ -112,7 +112,7 @@ Proof. iSplitR "Hsim". { do 4 iExists _; destruct σ_s; iFrame. iFrame "Hsrel". done. } simpl. rewrite Hpoison. subst sz. iSplit; last done. iApply "Hsim". - } + } *) edestruct trees_equal_allows_more_access as (trs_t'&Htrst). 1: done. 1: eapply Hwf_s. 1,2,3: rewrite ?Hscs_eq; eapply Hwf_t. 1: done. 1: done. 1: by eapply mk_is_Some. opose proof (trees_equal_preserved_by_access _ _ _ _ _ _ _ Hstrs_eq _ Htrss Htrst) as Hstrs_eq'. @@ -123,7 +123,7 @@ Proof. { iPureIntro. do 3 eexists. eapply copy_base_step'. 1-3: done. rewrite -Hscs_eq. done. } (* we keep the base_step hypotheses to use the [base_step_wf] lemma below *) iIntros (e_t' efs_t σ_t') "%Hhead_t". - specialize (head_copy_inv _ _ _ _ _ _ _ _ Hhead_t) as (->&[((Hnotree&->&Hpoison&Hheapsome)&Hcontains_t)|(tr'&vr_t'&->&Hσ_t'&H3&[(Hcontains_t&H4&_)|([]%Hsz&_&_)])]); first congruence. + specialize (head_copy_inv _ _ _ _ _ _ _ _ Hhead_t) as (->&tr'&vr_t'&->&Hσ_t'&H3&[(Hcontains_t&H4&_)|([]%Hsz&_&_)]). assert (vr_t' = vr_t) as -> by congruence. assert (tr' = trs_t') as -> by congruence. clear H3 H4. @@ -190,7 +190,7 @@ Proof. } iSplitL; last done. - iApply ("Hsim" with "Hs Ht Htk"). iLeft. iPureIntro. + iApply ("Hsim" with "Hs Ht Htk"). iPureIntro. eapply read_range_list_to_heaplet_read_memory_strict in Hreads. 2: done. 2: intros i Hi; specialize (Howns i Hi) as (_&H); exact H. eapply read_range_list_to_heaplet_read_memory_strict in Hreadt. 2: done. @@ -203,37 +203,37 @@ Qed. Lemma sim_into_read_for_simulation v_res_t v_res_s v_rd_t v_rd_s l_rd t : let sz := length v_rd_t in value_rel v_rd_t v_rd_s -∗ - (⌜v_res_s = v_rd_s ∧ v_res_t = v_rd_t⌠∨ ispoison v_res_s l_rd t sz ∗ ispoison v_res_t l_rd t sz) -∗ + (⌜v_res_s = v_rd_s ∧ v_res_t = v_rd_t⌠(*∨ ispoison v_res_s l_rd t sz ∗ ispoison v_res_t l_rd t sz*)) -∗ will_read_in_simulation v_rd_s v_res_t l_rd t. Proof. intros sz. iIntros "Hv1 Hor". iPoseProof (value_rel_length with "Hv1") as "%Hlen". - iDestruct "Hor" as "[(->&->)|(Hp1&Hp2)]". - { iLeft. done. } + iDestruct "Hor" as "(->&->)". + { done. } (* iRight. subst sz. iDestruct "Hp2" as "(%i&(_&%HH)&_)". rewrite HH. rewrite length_replicate Hlen. iSplit; first done. iDestruct "Hp1" as "(%ip&(%H1&%H2)&Hpp)". iExists ip. iSplit; last done. rewrite length_replicate. iPureIntro; split. 2: done. - rewrite H2 length_replicate in H1. lia. + rewrite H2 length_replicate in H1. lia. *) Qed. -Lemma sim_read_result_value_rel v_res_t v_res_s v_rd_t v_rd_s l_rd t : +Lemma sim_read_result_value_rel v_res_t v_res_s v_rd_t v_rd_s : let sz := length v_rd_t in value_rel v_rd_t v_rd_s -∗ - (⌜v_res_s = v_rd_s ∧ v_res_t = v_rd_t⌠∨ ispoison v_res_s l_rd t sz ∗ ispoison v_res_t l_rd t sz) -∗ + (⌜v_res_s = v_rd_s ∧ v_res_t = v_rd_t⌠(* ∨ ispoison v_res_s l_rd t sz ∗ ispoison v_res_t l_rd t sz *) ) -∗ value_rel v_res_t v_res_s. Proof. intros sz. iIntros "Hv1 Hor". iPoseProof (value_rel_length with "Hv1") as "%Hlen". - iDestruct "Hor" as "[(->&->)|(Hp1&Hp2)]". - { done. } + iDestruct "Hor" as "(->&->)". + { done. } (* subst sz. iDestruct "Hp2" as "(%i&(_&%HH)&_)". rewrite HH. iDestruct "Hp1" as "(%ip&(%H1&%H2)&Hpp)". rewrite H2. iApply big_sepL2_forall. iSplit. { rewrite length_replicate //. } - iIntros (k x1 x2 (->&_)%lookup_replicate_1 (->&_)%lookup_replicate_1). done. + iIntros (k x1 x2 (->&_)%lookup_replicate_1 (->&_)%lookup_replicate_1). done. *) Qed. diff --git a/theories/tree_borrows/steps_access.v b/theories/tree_borrows/steps_access.v deleted file mode 100755 index e894619c123a49fdb77b0cfb93a8c0de000e1060..0000000000000000000000000000000000000000 --- a/theories/tree_borrows/steps_access.v +++ /dev/null @@ -1,282 +0,0 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - -From simuliris.tree_borrows Require Export defs steps_foreach. -From iris.prelude Require Import options. - -(* Kept for now as an easy reference of the lemmas that SB needed -Lemma access1_in_stack stk kind t cids n stk' : - access1 stk kind t cids = Some (n, stk') → - ∃ it, it ∈ stk ∧ it.(tg) = t ∧ it.(perm) ≠Disabled. -Proof. - rewrite /access1. case find_granting as [gip|] eqn:Eq1; [|done]. - apply fmap_Some in Eq1 as [[i it] [(IN & [GR Eq] & FR)%list_find_Some EQ]]. - intros ?. exists it. split; last split; [|done|]. - - by eapply elem_of_list_lookup_2. - - intros Eq1. by rewrite Eq1 in GR. -Qed. - -Lemma access1_tagged_sublist stk kind bor cids n stk' : - access1 stk kind bor cids = Some (n, stk') → tagged_sublist stk' stk. -Proof. - rewrite /access1. case find_granting as [gip|]; [|done]. simpl. - destruct kind. - - case replace_check as [stk1|] eqn:Eq; [|done]. - simpl. intros. simplify_eq. - rewrite -{2}(take_drop gip.1 stk). apply tagged_sublist_app; [|done]. - move : Eq. by apply replace_check_tagged_sublist. - - case find_first_write_incompatible as [idx|]; [|done]. simpl. - case remove_check as [stk1|] eqn:Eq; [|done]. - simpl. intros. simplify_eq. - rewrite -{2}(take_drop gip.1 stk). apply tagged_sublist_app; [|done]. - move : Eq. by apply remove_check_tagged_sublist. -Qed. - -Lemma access1_non_empty stk kind bor cids n stk' : - access1 stk kind bor cids = Some (n, stk') → stk' ≠[]. -Proof. - rewrite /access1. case find_granting as [gip|] eqn:Eq1; [|done]. - apply fmap_Some in Eq1 as [[i it] [[IN ?]%list_find_Some EQ]]. - subst gip; simpl. - have ?: drop i stk ≠[]. - { move => ND. move : IN. by rewrite -(Nat.add_0_r i) -(lookup_drop) ND /=. } - destruct kind. - - case replace_check as [stk1|]; [|done]. - simpl. intros ?. simplify_eq => /app_nil [_ ?]. by subst. - - case find_first_write_incompatible as [?|]; [|done]. simpl. - case remove_check as [?|]; [|done]. - simpl. intros ?. simplify_eq => /app_nil [_ ?]. by subst. -Qed. - -Lemma for_each_access1 α nxtc l n tg kind α' : - for_each α l n false - (λ stk, nstk' ↠access1 stk kind tg nxtc; Some nstk'.2) = Some α' → - ∀ (l: loc) stk', α' !! l = Some stk' → ∃ stk, α !! l = Some stk ∧ - tagged_sublist stk' stk ∧ (stk ≠[] → stk' ≠[]). -Proof. - intros EQ. destruct (for_each_lookup _ _ _ _ _ EQ) as [EQ1 [EQ2 EQ3]]. - intros l1 stk1 Eq1. - case (decide (l1.1 = l.1)) => [Eql|NEql]; - [case (decide (l.2 ≤ l1.2 < l.2 + n)) => [[Le Lt]|NIN]|]. - - have Eql2: l1 = l +â‚— Z.of_nat (Z.to_nat (l1.2 - l.2)). { - destruct l, l1. move : Eql Le => /= -> ?. - rewrite /shift_loc /= Z2Nat.id; [|lia]. f_equal. lia. } - destruct (EQ2 (Z.to_nat (l1.2 - l.2)) stk1) - as [stk [Eq [[n1 stk'] [Eq' Eq0]]%bind_Some]]; - [rewrite -(Nat2Z.id n) -Z2Nat.inj_lt; lia|by rewrite -Eql2|]. - exists stk. split; [by rewrite Eql2|]. simplify_eq. - split; [by eapply access1_tagged_sublist|intros; by eapply access1_non_empty]. - - exists stk1. split; [|done]. rewrite -EQ3; [done|]. - intros i Lt Eq. apply NIN. rewrite Eq /=. lia. - - exists stk1. split; [|done]. rewrite -EQ3; [done|]. - intros i Lt Eq. apply NEql. by rewrite Eq. -Qed. - -Lemma for_each_access1_non_empty α cids l n tg kind α' : - for_each α l n false - (λ stk, nstk' ↠access1 stk kind tg cids; Some nstk'.2) = Some α' → - wf_non_empty α → wf_non_empty α'. -Proof. - move => /for_each_access1 EQ1 WF ?? /EQ1 [? [? [? NE]]]. by eapply NE, WF. -Qed. - -Lemma access1_stack_item_tagged_NoDup stk kind bor cids n stk' : - access1 stk kind bor cids = Some (n, stk') → - stack_item_tagged_NoDup stk → stack_item_tagged_NoDup stk'. -Proof. - rewrite /access1. case find_granting as [gip|] eqn:Eq1; [|done]. - apply fmap_Some in Eq1 as [[i it] [[IN ?]%list_find_Some EQ]]. - subst gip; simpl. - destruct kind. - - case replace_check as [stk1|] eqn:Eqc ; [|done]. - simpl. intros ?. simplify_eq. - rewrite -{1}(take_drop n stk). move : Eqc. - by apply replace_check_stack_item_tagged_NoDup_2. - - case find_first_write_incompatible as [?|]; [|done]. simpl. - case remove_check as [?|] eqn:Eqc ; [|done]. - simpl. intros ?. simplify_eq. - rewrite -{1}(take_drop n stk). move : Eqc. - apply remove_check_stack_item_tagged_NoDup_2. -Qed. - -Lemma access1_read_eq it1 it2 stk tag t cids n stk': - stack_item_tagged_NoDup stk → - access1 stk AccessRead tag cids = Some (n, stk') → - it1 ∈ stk → it2 ∈ stk' → - it2.(perm) ≠Disabled → - it1.(tg) = Tagged t → it2.(tg) = Tagged t → it1 = it2. -Proof. - intros ND ACC. - have ND' := access1_stack_item_tagged_NoDup _ _ _ _ _ _ ACC ND. - move : ACC. rewrite /= /access1 /=. - case find_granting as [[idx pm]|] eqn:Eq1; [|done]. simpl. - case replace_check as [stk1|] eqn:Eq2; [|done]. - simpl. intros ?. simplify_eq. intros In1. - have SUB:= replace_check_tagged_sublist _ _ _ Eq2. - rewrite elem_of_app. intros In2 ND2. - destruct In2 as [In2|In2]. - - specialize (SUB _ In2) as (it3 & In3 & Eqt3 & Eqp3 & ND3). - specialize (ND3 ND2). - have ?: it3 = it2. - { destruct it2, it3. simpl in *. by simplify_eq. } - subst it3. - apply (stack_item_tagged_NoDup_eq _ _ _ _ ND); [done|]. - rewrite -{1}(take_drop n stk) elem_of_app. by left. - - apply (stack_item_tagged_NoDup_eq _ _ _ _ ND); [done|]. - rewrite -{1}(take_drop n stk) elem_of_app. by right. -Qed. - -Lemma for_each_access1_stack_item α nxtc cids nxtp l n tg kind α' : - for_each α l n false - (λ stk, nstk' ↠access1 stk kind tg cids; Some nstk'.2) = Some α' → - wf_stacks α nxtp nxtc → wf_stacks α' nxtp nxtc. -Proof. - intros ACC WF l' stk' Eq'. - destruct (for_each_access1 _ _ _ _ _ _ _ ACC _ _ Eq') as [stk [Eq [SUB NN]]]. - split. - - move => ? /SUB [? [IN [-> [-> ?]]]]. by apply (proj1 (WF _ _ Eq) _ IN). - - clear SUB NN. - destruct (for_each_lookup_case _ _ _ _ _ ACC _ _ _ Eq Eq') as [?|[Eqf ?]]. - { subst. by apply (WF _ _ Eq). } - destruct (access1 stk kind tg cids) as [[]|] eqn:Eqf'; [|done]. - simpl in Eqf. simplify_eq. - eapply access1_stack_item_tagged_NoDup; eauto. by apply (WF _ _ Eq). -Qed. -*) - -(** Dealloc *) -(* -Lemma for_each_dealloc_lookup α l n f α' : - for_each α l n true f = Some α' → - (∀ (i: nat), (i < n)%nat → α' !! (l +â‚— i) = None) ∧ - (∀ (l': loc), (∀ (i: nat), (i < n)%nat → l' ≠l +â‚— i) → α' !! l' = α !! l'). -Proof. - revert α. induction n as [|n IH]; intros α; simpl. - { move => [<-]. split; intros ??; by [lia|]. } - case (α !! (l +â‚— n)) as [stkn|] eqn:Eqn; [|done] => /=. - case f as [stkn'|] eqn: Eqn'; [|done] => /= /IH [IH1 IH2]. split. - - intros i Lt. case (decide (i = n)) => Eq'; [subst i|]. - + rewrite IH2; [by apply lookup_delete|]. - move => ?? /shift_loc_inj /Nat2Z.inj ?. by lia. - + apply IH1. by lia. - - intros l' Lt. rewrite IH2. - + rewrite lookup_delete_ne; [done|]. move => Eql'. apply (Lt n); by [lia|]. - + move => ??. apply Lt. lia. -Qed. - -Lemma for_each_dealloc_lookup_Some α l n f α' : - for_each α l n true f = Some α' → - ∀ l' stk', α' !! l' = Some stk' → - (∀ i : nat, (i < n)%nat → l' ≠l +â‚— i) ∧ α !! l' = Some stk'. -Proof. - intros EQ. destruct (for_each_dealloc_lookup _ _ _ _ _ EQ) as [EQ1 EQ2]. - intros l1 stk1 Eq1. - destruct (block_case l l1 n) as [NEql|Eql]. - - rewrite -EQ2 //. - - destruct Eql as (i & Lt & ?). subst l1. rewrite EQ1 // in Eq1. -Qed. -*) - -Lemma free_mem_lookup l n h : - (∀ (i: nat), (i < n)%nat → free_mem l n h !! (l +â‚— i) = None) ∧ - (∀ (l': loc), (∀ (i: nat), (i < n)%nat → l' ≠l +â‚— i) → - free_mem l n h !! l' = h !! l'). -Proof. - revert l. induction n as [|n IH]; intros l; simpl. - { split; intros ??; by [lia|]. } split. - - intros i Lt. destruct i as [|i]. - + rewrite shift_loc_0 lookup_delete //. - + rewrite lookup_delete_ne. - * specialize (IH (l +â‚— 1))as [IH _]. - rewrite (_: l +â‚— S i = l +â‚— 1 +â‚— i). - { apply IH. lia. } - { rewrite shift_loc_assoc. f_equal. lia. } - * rewrite -{1}(shift_loc_0 l). - move => /shift_loc_inj ?. lia. - - intros l' Lt. - rewrite lookup_delete_ne. - + apply IH. intros i Lti. - rewrite (_: l +â‚— 1 +â‚— i = l +â‚— S i). - * apply Lt. lia. - * rewrite shift_loc_assoc. f_equal. lia. - + rewrite -(shift_loc_0_nat l). intros ?. subst l'. apply (Lt O); [lia|done]. -Qed. - -Lemma free_mem_lookup_case l' l n h : - (∀ i : nat, (i < n)%nat → l' ≠l +â‚— i) ∧ free_mem l n h !! l' = h !! l' ∨ - ∃ i : nat, (i < n)%nat ∧ l' = l +â‚— i ∧ free_mem l n h !! (l +â‚— i) = None. -Proof. - destruct (free_mem_lookup l n h) as [EQ1 EQ2]. - destruct (block_case l l' n) as [NEql|Eql]. - - left. rewrite -EQ2 //. - - right. destruct Eql as (i & Lt & ?). exists i. do 2 (split; [done|]). - subst l'. by apply EQ1. -Qed. - -Lemma free_mem_dom_inv l' l n h: - l' ∈ dom (free_mem l n h) → - l' ∈ dom h ∧ - (∀ i : nat, (i < n)%nat → l' ≠l +â‚— i) ∧ free_mem l n h !! l' = h !! l'. -Proof. - intros [? EqD]%elem_of_dom. - destruct (free_mem_lookup_case l' l n h) as [Eqn|(i & Lt & ? & EqN)]. - - split; [|done]. apply elem_of_dom. destruct Eqn as [? Eqn]. - rewrite -Eqn. by eexists. - - exfalso. subst l'. by rewrite EqD in EqN. -Qed. - - - -Lemma init_mem_lookup_fresh_poison blk off (n:nat) h : - 0 ≤ off ∧ off < n → - init_mem (blk, 0) n h !! (blk, off) = Some ScPoison. -Proof. - intros (Hpos & Hlt). - pose proof (init_mem_lookup (blk, 0) n h) as (Hinit1&_). - ospecialize (Hinit1 (Z.to_nat off) _); first lia. - rewrite /= /shift_loc /= Z.add_0_l Z2Nat.id // in Hinit1. -Qed. - -Lemma init_mem_lookup_fresh_None blk off (n:nat) h : - (forall off, (blk, off) ∉ dom h) → - (off < 0 ∨ n ≤ off) → - init_mem (blk, 0) n h !! (blk, off) = None. -Proof. - intros Hfresh Hout. - pose proof (init_mem_lookup (blk, 0) n h) as (_&Hinit2). - rewrite (Hinit2 (blk, off)). - + eapply not_elem_of_dom, Hfresh. - + intros i Hlt. - rewrite /= /shift_loc /= Z.add_0_l. - intros [= ->]. destruct Hout as [Hout|Hout]; lia. -Qed. - -Lemma init_mem_lookup_fresh_old blk blk' off (n:nat) h : - blk ≠blk' → - init_mem (blk, 0) n h !! (blk', off) = h !! (blk', off). -Proof. - intros Hfresh. - pose proof (init_mem_lookup (blk, 0) n h) as (_&Hinit2). - apply Hinit2. - intros ? _ [=]. done. -Qed. - - -Lemma init_mem_lookup_fresh_inv blk blk' off (n:nat) h k : - (forall off, (blk, off) ∉ dom h) → - init_mem (blk, 0) n h !! (blk', off) = k → - (k = Some ScPoison ∧ blk = blk' ∧ 0 ≤ off ∧ off < n) -∨ (k = None ∧ blk = blk' ∧ (off < 0 ∨ n ≤ off)) -∨ (k = h !! (blk', off) ∧ blk ≠blk'). -Proof. - intros Hfresh Hinit. - destruct (decide (blk = blk')) as [Heqblk|Hne]. - 1: subst blk'; destruct (decide (0 ≤ off)) as [Hpos|Hneg]. - 1: destruct (decide (off < n)) as [Hlt|Hge]. - { left. subst k. split_and!; try done. by rewrite init_mem_lookup_fresh_poison. } - 1-2: right; left; split_and!; try done; last lia. - 1-2: subst k; rewrite init_mem_lookup_fresh_None; try done; lia. - { right. right. split; last done. subst k. by apply init_mem_lookup_fresh_old. } -Qed. - diff --git a/theories/tree_borrows/steps_foreach.v b/theories/tree_borrows/steps_foreach.v index fd2b12066bcc5259093ccdf83fd12d00ddfaabcc..ba77c310d12e413f4beb5df0e52883e99a37a252 100755 --- a/theories/tree_borrows/steps_foreach.v +++ b/theories/tree_borrows/steps_foreach.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) - From simuliris.tree_borrows Require Export defs. From iris.prelude Require Import options. @@ -139,3 +135,105 @@ Lemma extend_trees_lookup_ne trs tg off sz blk blk' : Proof. apply lookup_insert_ne. Qed. +Lemma free_mem_lookup l n h : + (∀ (i: nat), (i < n)%nat → free_mem l n h !! (l +â‚— i) = None) ∧ + (∀ (l': loc), (∀ (i: nat), (i < n)%nat → l' ≠l +â‚— i) → + free_mem l n h !! l' = h !! l'). +Proof. + revert l. induction n as [|n IH]; intros l; simpl. + { split; intros ??; by [lia|]. } split. + - intros i Lt. destruct i as [|i]. + + rewrite shift_loc_0 lookup_delete //. + + rewrite lookup_delete_ne. + * specialize (IH (l +â‚— 1))as [IH _]. + rewrite (_: l +â‚— S i = l +â‚— 1 +â‚— i). + { apply IH. lia. } + { rewrite shift_loc_assoc. f_equal. lia. } + * rewrite -{1}(shift_loc_0 l). + move => /shift_loc_inj ?. lia. + - intros l' Lt. + rewrite lookup_delete_ne. + + apply IH. intros i Lti. + rewrite (_: l +â‚— 1 +â‚— i = l +â‚— S i). + * apply Lt. lia. + * rewrite shift_loc_assoc. f_equal. lia. + + rewrite -(shift_loc_0_nat l). intros ?. subst l'. apply (Lt O); [lia|done]. +Qed. + +Lemma free_mem_lookup_case l' l n h : + (∀ i : nat, (i < n)%nat → l' ≠l +â‚— i) ∧ free_mem l n h !! l' = h !! l' ∨ + ∃ i : nat, (i < n)%nat ∧ l' = l +â‚— i ∧ free_mem l n h !! (l +â‚— i) = None. +Proof. + destruct (free_mem_lookup l n h) as [EQ1 EQ2]. + destruct (block_case l l' n) as [NEql|Eql]. + - left. rewrite -EQ2 //. + - right. destruct Eql as (i & Lt & ?). exists i. do 2 (split; [done|]). + subst l'. by apply EQ1. +Qed. + +Lemma free_mem_dom_inv l' l n h: + l' ∈ dom (free_mem l n h) → + l' ∈ dom h ∧ + (∀ i : nat, (i < n)%nat → l' ≠l +â‚— i) ∧ free_mem l n h !! l' = h !! l'. +Proof. + intros [? EqD]%elem_of_dom. + destruct (free_mem_lookup_case l' l n h) as [Eqn|(i & Lt & ? & EqN)]. + - split; [|done]. apply elem_of_dom. destruct Eqn as [? Eqn]. + rewrite -Eqn. by eexists. + - exfalso. subst l'. by rewrite EqD in EqN. +Qed. + + + +Lemma init_mem_lookup_fresh_poison blk off (n:nat) h : + 0 ≤ off ∧ off < n → + init_mem (blk, 0) n h !! (blk, off) = Some ScPoison. +Proof. + intros (Hpos & Hlt). + pose proof (init_mem_lookup (blk, 0) n h) as (Hinit1&_). + ospecialize (Hinit1 (Z.to_nat off) _); first lia. + rewrite /= /shift_loc /= Z.add_0_l Z2Nat.id // in Hinit1. +Qed. + +Lemma init_mem_lookup_fresh_None blk off (n:nat) h : + (forall off, (blk, off) ∉ dom h) → + (off < 0 ∨ n ≤ off) → + init_mem (blk, 0) n h !! (blk, off) = None. +Proof. + intros Hfresh Hout. + pose proof (init_mem_lookup (blk, 0) n h) as (_&Hinit2). + rewrite (Hinit2 (blk, off)). + + eapply not_elem_of_dom, Hfresh. + + intros i Hlt. + rewrite /= /shift_loc /= Z.add_0_l. + intros [= ->]. destruct Hout as [Hout|Hout]; lia. +Qed. + +Lemma init_mem_lookup_fresh_old blk blk' off (n:nat) h : + blk ≠blk' → + init_mem (blk, 0) n h !! (blk', off) = h !! (blk', off). +Proof. + intros Hfresh. + pose proof (init_mem_lookup (blk, 0) n h) as (_&Hinit2). + apply Hinit2. + intros ? _ [=]. done. +Qed. + + +Lemma init_mem_lookup_fresh_inv blk blk' off (n:nat) h k : + (forall off, (blk, off) ∉ dom h) → + init_mem (blk, 0) n h !! (blk', off) = k → + (k = Some ScPoison ∧ blk = blk' ∧ 0 ≤ off ∧ off < n) +∨ (k = None ∧ blk = blk' ∧ (off < 0 ∨ n ≤ off)) +∨ (k = h !! (blk', off) ∧ blk ≠blk'). +Proof. + intros Hfresh Hinit. + destruct (decide (blk = blk')) as [Heqblk|Hne]. + 1: subst blk'; destruct (decide (0 ≤ off)) as [Hpos|Hneg]. + 1: destruct (decide (off < n)) as [Hlt|Hge]. + { left. subst k. split_and!; try done. by rewrite init_mem_lookup_fresh_poison. } + 1-2: right; left; split_and!; try done; last lia. + 1-2: subst k; rewrite init_mem_lookup_fresh_None; try done; lia. + { right. right. split; last done. subst k. by apply init_mem_lookup_fresh_old. } +Qed. + diff --git a/theories/tree_borrows/steps_inv.v b/theories/tree_borrows/steps_inv.v index 998037c114e8cfe56efb74d009881fbdbe3d6702..bfbd451b3aca0a6a9588eec7cb7096b585d2461d 100755 --- a/theories/tree_borrows/steps_inv.v +++ b/theories/tree_borrows/steps_inv.v @@ -17,11 +17,11 @@ Proof. intros Hhead. inv_base_step. eauto 8. Qed. Lemma head_copy_inv (P : prog) l bor sz σ σ' e' efs : base_step P (Copy (Place l bor sz)) σ e' σ' efs → efs = [] ∧ -((apply_within_trees (memory_access AccessRead (scs σ) bor (l.2, sz)) l.1 σ.(strs) = None ∧ +((*(apply_within_trees (memory_access AccessRead (scs σ) bor (l.2, sz)) l.1 σ.(strs) = None ∧ σ = σ' ∧ e' = ValR (replicate sz ScPoison)%V ∧ is_Some (read_mem l sz σ.(shp))) ∧ - trees_contain bor σ.(strs) l.1 ∨ + trees_contain bor σ.(strs) l.1 ∨ *) ∃ trs' (v':value), e' = (v')%E ∧ σ' = mkState σ.(shp) trs' σ.(scs) σ.(snp) σ.(snc) ∧ diff --git a/theories/tree_borrows/steps_preserve.v b/theories/tree_borrows/steps_preserve.v index 15d61d4562bd31bc767bfdaa1843c1a5ff8d4ba2..0bddf4e972046c2809aedeaf9b99c1f64c177853 100644 --- a/theories/tree_borrows/steps_preserve.v +++ b/theories/tree_borrows/steps_preserve.v @@ -2,9 +2,18 @@ From iris.prelude Require Import prelude options. From simuliris.tree_borrows Require Import lang_base notation bor_semantics tree tree_lemmas bor_lemmas defs. From iris.prelude Require Import options. +(** Lemmas about borrow steps preserving properties of the tree. + This is related to [steps_wf.v], but where [steps_wf] states lemmas about + preservation of well-formedness by all borrow steps, these are lower-level. + Many lemmas here will seem trivial (e.g. if you have a tree in which a tag + is unique and you apply a tag-preserving function, the tag is still unique). *) + (* Any function that operates only on permissions (which is all transitions steps) leaves the tag and protector unchanged which means that most of the preservation lemmas - are trivial once we get to the level of items *) + are trivial once we get to the level of items. + Preservation of metadata includes preservation of relationships since + the parent-child relation is defined by the relative location of tags + (which are metadata). *) Definition preserve_item_metadata (fn:item -> option item) := forall it it', fn it = Some it' -> it.(itag) = it'.(itag) /\ it.(iprot) = it'.(iprot) /\ it.(initp) = it'.(initp). @@ -140,9 +149,10 @@ Proof. erewrite new_item_has_tag; done. Qed. +(** Detailed specification of the effects of one access. + This is to trees what [mem_apply_range'_spec] is to ranges. *) Lemma apply_access_spec_per_node {tr affected_tag access_tag pre fn cids range tr'} - (*(ExAcc : tree_contains access_tag tr)*) (ExAff : tree_contains affected_tag tr) (UnqAff : tree_item_determined affected_tag pre tr) (Access : tree_apply_access fn cids access_tag range tr = Some tr') @@ -182,147 +192,8 @@ Proof. tauto. Qed. -Lemma bor_local_step_preserves_contains - {tg tr tr' cids cids' evt} - (Ex : tree_contains tg tr) - (Step : bor_local_step - tr cids - evt - tr' cids') - : tree_contains tg tr'. -Proof. - inversion Step as [????? ACC| | |]; subst. - - (* Access *) - erewrite <- access_preserves_tags; [eassumption|exact ACC]. - - (* InitCall *) assumption. - - (* EndCall *) assumption. - - (* Retag *) - eapply insertion_preserves_tags; eauto. -Qed. - -Lemma bor_local_step_retag_produces_contains_determined - {tgp tg tr tr' cids cids' pk im rk cid} - (Step : bor_local_step - tr cids - (RetagBLEvt tgp tg pk im cid rk) - tr' cids') - : ∃ it, create_new_item tg pk im rk cid = Some it ∧ tree_contains tg tr' - /\ tree_item_determined tg it tr'. -Proof. - inversion Step as [| | |?????????? (it&Hit&RETAG_EFFECT)%bind_Some]; subst. - exists it. split; first done. - split. - - eapply (insertion_contains) with (cids := cids'); first done. - eapply bind_Some. by exists it. - - injection RETAG_EFFECT; intros; subst. - eapply inserted_determined. 2: done. - erewrite new_item_has_tag. 2: exact Hit. done. -Qed. - -Lemma bor_local_step_preserves_determined_easy - {tg tr it tr' cids cids' evt} - (Ex : tree_contains tg tr) - (Unq : tree_item_determined tg it tr) - (Step : bor_local_step tr cids evt tr' cids') - : exists it', - tree_item_determined tg it' tr' - /\ match evt with - | AccessBLEvt _ _ _ => iprot it = iprot it' - | InitCallBLEvt _ - | EndCallBLEvt _ - | RetagBLEvt _ _ _ _ _ _ - | SilentBLEvt => it = it' - end. -Proof. - inversion Step as [???? EXISTS_TAG ACC| | |????????? FRESH_CHILD RETAG_EFFECT]; subst. - - (* Access *) - destruct (apply_access_spec_per_node Ex Unq ACC) as [?[Spec[_?]]]. - eexists; split; eauto. - symmetry in Spec. eapply item_apply_access_preserves_metadata; exact Spec. - - eexists; split; [|reflexivity]; assumption. - - eexists; split; [|reflexivity]; assumption. - - (* Retag *) - eexists; split; [|reflexivity]. - eapply create_child_preserves_determined; [|exact Unq|exact RETAG_EFFECT]. - intro; subst. destruct (FRESH_CHILD Ex). -Qed. - -Lemma bor_local_step_eqv_rel - {tg tg' tr tr' cids cids' evt} - (Ex : tree_contains tg tr) - (Ex' : tree_contains tg' tr) - (Step : bor_local_step tr cids evt tr' cids') - : ParentChildIn tg tg' tr <-> ParentChildIn tg tg' tr'. -Proof. - inversion Step as [????? ACC| | |????????? FRESH_CHILD (x&Hx&RETAG_EFFECT)%bind_Some]; subst. - - (* Access *) - rewrite access_eqv_rel; [|apply ACC]. - tauto. - - tauto. - - tauto. - - (* Retag *) - injection RETAG_EFFECT; intros; subst. - rewrite <- insert_eqv_rel. - * tauto. - * erewrite new_item_has_tag; last done. - intro; subst; destruct (FRESH_CHILD Ex). - * erewrite new_item_has_tag; last done. - intro; subst; destruct (FRESH_CHILD Ex'). -Qed. - -Lemma bor_local_step_eqv_imm_rel - {tg tg' tr tr' cids cids' evt} - (Ex : tree_contains tg tr) - (Ex' : tree_contains tg' tr) - (Step : bor_local_step tr cids evt tr' cids') - : ImmediateParentChildIn tg tg' tr <-> ImmediateParentChildIn tg tg' tr'. -Proof. - inversion Step as [????? ACC| | |????????? FRESH_CHILD (x&Hx&RETAG_EFFECT)%bind_Some]; subst. - - (* Access *) - rewrite access_eqv_immediate_rel; [|apply ACC]. - tauto. - - tauto. - - tauto. - - (* Retag *) - injection RETAG_EFFECT; intros; subst. - rewrite <- insert_eqv_imm_rel. - * tauto. - * erewrite new_item_has_tag; last done. - intro; subst; destruct (FRESH_CHILD Ex). - * erewrite new_item_has_tag; last done. - intro; subst; destruct (FRESH_CHILD Ex'). -Qed. - -Lemma bor_local_step_retag_produces_rel - {tgp tg tr tr' cids cids' pk im rk cid} - (Step : bor_local_step - tr cids - (RetagBLEvt tgp tg pk im rk cid) - tr' cids') - : ParentChildIn tgp tg tr'. -Proof. - inversion Step as [????? ACC| | |???????? EXISTS_PARENT FRESH_CHILD (x&Hx&RETAG_EFFECT)%bind_Some]; subst. - injection RETAG_EFFECT; intros; subst. - eapply insert_produces_ParentChild. - * eapply new_item_has_tag. done. - * intro; subst; destruct (FRESH_CHILD EXISTS_PARENT). -Qed. - -Lemma bor_local_step_retag_order_nonparent - {tgp tg tg' tr tr' cids cids' pk im rk cid} - (Ex' : tree_contains tg' tr) - (Step : bor_local_step - tr cids - (RetagBLEvt tgp tg pk im rk cid) - tr' cids') - : ~ParentChildIn tg tg' tr'. -Proof. - inversion Step as [????? ACC| | |???????? EXISTS_PARENT FRESH_CHILD (x&Hx&RETAG_EFFECT)%bind_Some]; subst. - injection RETAG_EFFECT; intros; subst. - eapply insertion_order_nonparent with (cids:=cids'). 1-3: eassumption. - eapply bind_Some; by eexists. -Qed. - +(** Reachability of a state behaves as expected in between applications + of functions compatible with [reach]. *) Lemma apply_access_perm_preserves_backward_reach {pre post kind rel b p0} (Access : apply_access_perm kind rel b pre = Some post) @@ -442,415 +313,6 @@ Proof. - rewrite Spec; tauto. Qed. -Lemma bor_local_step_preserves_backward_reach - {tg tr tr' cids cids' pre post evt p0 z} - (Ex : tree_contains tg tr) - (UnqPre : tree_item_determined tg pre tr) - (Step : bor_local_step tr cids evt tr' cids') - (UnqPost : tree_item_determined tg post tr') - : reach p0 (item_perm_at_loc pre z) -> reach p0 (item_perm_at_loc post z). -Proof. - inversion Step as [???? EXISTS_TAG ACC| | |]; subst. - - apply (memory_access_preserves_backward_reach Ex UnqPre EXISTS_TAG ACC UnqPost). - - rewrite (tree_determined_unify Ex UnqPre UnqPost); tauto. - - rewrite (tree_determined_unify Ex UnqPre UnqPost); tauto. - - pose proof (bor_local_step_preserves_contains Ex Step) as ExPost'. - pose proof (bor_local_step_preserves_determined_easy Ex UnqPre Step) as [it' [UnqPost' Eq]]; subst; simpl in UnqPost'. - rewrite (tree_determined_unify ExPost' UnqPost' UnqPost); tauto. -Qed. - -Lemma bor_local_step_preserves_forward_unreach - {tg tr tr' cids cids' pre post evt p0 z} - (Ex : tree_contains tg tr) - (UnqPre : tree_item_determined tg pre tr) - (Step : bor_local_step tr cids evt tr' cids') - (UnqPost : tree_item_determined tg post tr') - : ~reach (item_perm_at_loc pre z) p0 -> ~reach (item_perm_at_loc post z) p0. -Proof. - inversion Step as [???? EXISTS_TAG ACC| | |]; subst. - - apply (memory_access_preserves_forward_unreach Ex UnqPre EXISTS_TAG ACC UnqPost). - - rewrite (tree_determined_unify Ex UnqPre UnqPost); tauto. - - rewrite (tree_determined_unify Ex UnqPre UnqPost); tauto. - - pose proof (bor_local_step_preserves_contains Ex Step) as ExPost'. - pose proof (bor_local_step_preserves_determined_easy Ex UnqPre Step) as [it' [UnqPost' Eq]]; subst; simpl in UnqPost'. - rewrite (tree_determined_unify ExPost' UnqPost' UnqPost); tauto. -Qed. - -Lemma bor_local_step_preserves_protected_freeze_like - {tg tr tr' cids cids' pre post evt z} - (Ex : tree_contains tg tr) - (UnqPre : tree_item_determined tg pre tr) - (Prot : protector_is_active (iprot pre) cids) - (Step : bor_local_step tr cids evt tr' cids') - (UnqPost : tree_item_determined tg post tr') - : freeze_like (item_perm_at_loc pre z) -> freeze_like (item_perm_at_loc post z). -Proof. - inversion Step as [???? EXISTS_TAG ACC| | |]; subst. - - apply (memory_access_preserves_protected_freeze_like Ex UnqPre EXISTS_TAG Prot ACC UnqPost). - - rewrite (tree_determined_unify Ex UnqPre UnqPost); tauto. - - rewrite (tree_determined_unify Ex UnqPre UnqPost); tauto. - - pose proof (bor_local_step_preserves_contains Ex Step) as ExPost'. - pose proof (bor_local_step_preserves_determined_easy Ex UnqPre Step) as [it' [UnqPost' Eq]]; subst; simpl in UnqPost'. - rewrite (tree_determined_unify ExPost' UnqPost' UnqPost); tauto. -Qed. - -Lemma seq_always_build_forward - {invariant invariant'} - {tr cids evts tr' cids'} - (INV0 : invariant'.(seq_inv) tr cids) - (Preserve : forall tr cids tr' cids' evt, - bor_local_step tr cids evt tr' cids' -> - invariant.(seq_inv) tr cids -> - invariant'.(seq_inv) tr cids -> - invariant'.(seq_inv) tr' cids' - ) - (Seq : bor_local_seq invariant tr cids evts tr' cids') - : bor_local_seq invariant' tr cids evts tr' cids'. -Proof. - generalize dependent tr. - generalize dependent tr'. - generalize dependent cids. - generalize dependent cids'. - induction evts; move=> ????? Seq; inversion Seq; subst. - - constructor; assumption. - - econstructor; eauto. -Qed. - -Lemma seq_always_destruct_first - {invariant} - {tr cids evts tr' cids'} - (Seq : bor_local_seq invariant tr cids evts tr' cids') - : invariant.(seq_inv) tr cids. -Proof. inversion Seq; subst; assumption. Qed. - -Lemma seq_always_destruct_last - {invariant} - {tr cids evts tr' cids'} - (Seq : bor_local_seq invariant tr cids evts tr' cids') - : invariant.(seq_inv) tr' cids'. -Proof. - generalize dependent tr. - generalize dependent cids. - induction evts as [|?? IHevts]; move=> ?? Seq; inversion Seq; subst. - - assumption. - - eapply IHevts; eauto. -Qed. - -Lemma bor_local_step_deterministic - {tr cids evt tr1 cids1 tr2 cids2} - (Step1 : bor_local_step tr cids evt tr1 cids1) - (Step2 : bor_local_step tr cids evt tr2 cids2) - : tr1 = tr2 /\ cids1 = cids2. -Proof. - destruct evt; inversion Step1 as [????? ACC1| | |?????????? RETAG_EFFECT1]; - inversion Step2 as [????? ACC2| | |?????????? RETAG_EFFECT2]; subst. - - rewrite ACC1 in ACC2; injection ACC2; tauto. - - tauto. - - tauto. - - rewrite RETAG_EFFECT1 in RETAG_EFFECT2; injection RETAG_EFFECT2; tauto. -Qed. - -Lemma bor_local_seq_deterministic - {invariant tr cids evts tr1 cids1 tr2 cids2} - (Seq1 : bor_local_seq invariant tr cids evts tr1 cids1) - (Seq2 : bor_local_seq invariant tr cids evts tr2 cids2) - : tr1 = tr2 /\ cids1 = cids2. -Proof. - generalize dependent tr. - generalize dependent cids. - generalize dependent tr1. - generalize dependent cids1. - generalize dependent tr2. - generalize dependent cids2. - induction evts as [|?? IHevts]; move=> ?????? Seq1 Seq2; inversion Seq1 as [|??????? HEAD1]; inversion Seq2 as [|??????? HEAD2]. - - subst. tauto. - - pose proof (bor_local_step_deterministic HEAD1 HEAD2) as [??]; subst. - eapply IHevts; eauto. -Qed. - -Lemma bor_local_seq_forget - {invariant tr cids evts tr' cids'} - (Seq : bor_local_seq invariant tr cids evts tr' cids') - : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids'. -Proof. - generalize dependent tr. - generalize dependent cids. - induction evts as [|?? IHevts]; move=> ?? Seq; inversion Seq as [|??????? HEAD1]; subst. - - constructor; done. - - econstructor; [done|exact HEAD1|]. - eapply IHevts; assumption. -Qed. - -Lemma seq_always_build_direct - {invariant tr cids evts tr' cids'} - (PTR : forall tr cids, invariant.(seq_inv) tr cids) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : bor_local_seq invariant tr cids evts tr' cids'. -Proof. - generalize dependent tr. - generalize dependent cids. - induction evts; move=> ?? Seq; inversion Seq; subst. - + constructor; auto. - + econstructor; eauto. -Qed. - -Lemma seq_always_build_weaken - {invariant invariant' tr cids evts tr' cids'} - (WEAKEN : forall tr cids, invariant.(seq_inv) tr cids -> invariant'.(seq_inv) tr cids) - (Seq : bor_local_seq invariant tr cids evts tr' cids') - : bor_local_seq invariant' tr cids evts tr' cids'. -Proof. - generalize dependent tr. - generalize dependent cids. - induction evts; move=> ?? Seq; inversion Seq; subst. - + constructor; auto. - + econstructor; eauto. -Qed. - -Lemma seq_always_merge - {invariant1 invariant2 tr cids evts tr' cids'} - (Seq1 : bor_local_seq invariant1 tr cids evts tr' cids') - (Seq2 : bor_local_seq invariant2 tr cids evts tr' cids') - : bor_local_seq {| seq_inv:=fun tr cids => invariant1.(seq_inv) tr cids /\ invariant2.(seq_inv) tr cids|} tr cids evts tr' cids'. -Proof. - generalize dependent tr. - generalize dependent cids. - induction evts; move=> ?? Seq1 Seq2; inversion Seq1 as [|??????? HEAD1 REST1]; inversion Seq2 as [|??????? HEAD2 REST2]. - - constructor; split; assumption. - - pose proof (bor_local_step_deterministic HEAD1 HEAD2) as [??]; subst. - pose proof (bor_local_seq_deterministic (bor_local_seq_forget REST1) (bor_local_seq_forget REST2)) as [??]; subst. - econstructor; simpl; eauto. -Qed. - -Lemma bor_local_seq_always_contains - {tg tr cids tr' cids' evts} - (Ex : tree_contains tg tr) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : bor_local_seq {|seq_inv:=fun tr _ => (tree_contains tg) tr|} tr cids evts tr' cids'. -Proof. - eapply seq_always_build_forward; [assumption| |exact Seq]. - clear. - move=> ????? Step _ Ex; simpl in *. - eapply bor_local_step_preserves_contains; eassumption. -Qed. - -Lemma bor_local_seq_last_contains - {tg tr cids tr' cids' evts} - (Ex : tree_contains tg tr) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : tree_contains tg tr'. -Proof. - pose proof (seq_always_destruct_last (bor_local_seq_always_contains Ex Seq)). - assumption. -Qed. - -Lemma bor_local_seq_always_determined - {tg tr tr' prot cids cids' evts pre} - (Ex : tree_contains tg tr) - (Unq : tree_item_determined tg pre tr) - (ProtEq : iprot pre = prot) - (Seq : bor_local_seq {|seq_inv:=fun tr _ => (tree_contains tg) tr|} tr cids evts tr' cids') - : bor_local_seq {|seq_inv:=fun tr _ => exists it, tree_item_determined tg it tr /\ iprot it = prot|} tr cids evts tr' cids'. -Proof. - eapply seq_always_build_forward; [| |exact Seq]. - - eexists; split; eassumption. - - clear. simpl. move=> ???? evt Step Ex [?[Unq Prot]]. - destruct (bor_local_step_preserves_determined_easy Ex Unq Step) as [?[??]]. - eexists. - split; [eassumption|]. - destruct evt; subst; auto. -Qed. - -Lemma bor_local_seq_last_determined - {tg tr tr' cids cids' evts pre} - (Ex : tree_contains tg tr) - (Unq : tree_item_determined tg pre tr) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : exists post, tree_item_determined tg post tr' /\ iprot pre = iprot post. -Proof. - pose proof (bor_local_seq_always_contains Ex Seq) as AllEx. - destruct (seq_always_destruct_last (bor_local_seq_always_determined Ex Unq eq_refl AllEx)) as [?[??]]. - eexists; split; subst; eauto. -Qed. - -Lemma bor_local_seq_always_rel - {tg tg' tr tr' cids cids' evts} - (Rel : ParentChildIn tg tg' tr) - (Ex : tree_contains tg tr) - (Ex' : tree_contains tg' tr) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : bor_local_seq {|seq_inv:=fun tr _ => (ParentChildIn tg tg') tr|} tr cids evts tr' cids'. -Proof. - pose proof (seq_always_merge - (bor_local_seq_always_contains Ex Seq) - (bor_local_seq_always_contains Ex' Seq)) as AllExEx'. - eapply seq_always_build_forward; [assumption| |exact AllExEx']. - clear; simpl; move=> ????? Step [Ex Ex'] Rel. - rewrite <- (bor_local_step_eqv_rel Ex Ex' Step). - assumption. -Qed. - -Lemma bor_local_seq_always_unrel - {tg tg' tr tr' cids cids' evts} - (Rel : ~ParentChildIn tg tg' tr) - (Ex : tree_contains tg tr) - (Ex' : tree_contains tg' tr) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : bor_local_seq {|seq_inv:=fun tr _ => ~ParentChildIn tg tg' tr|} tr cids evts tr' cids'. -Proof. - pose proof (seq_always_merge - (bor_local_seq_always_contains Ex Seq) - (bor_local_seq_always_contains Ex' Seq)) as AllExEx'. - eapply seq_always_build_forward; [assumption| |exact AllExEx']. - clear; simpl; move=> ????? Step [Ex Ex'] Rel. - rewrite <- (bor_local_step_eqv_rel Ex Ex' Step). - assumption. -Qed. - -Lemma bor_local_seq_last_eqv_rel - {tg tg' tr tr' cids cids' evts} - (Ex : tree_contains tg tr) - (Ex' : tree_contains tg' tr) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : ParentChildIn tg tg' tr <-> ParentChildIn tg tg' tr'. -Proof. - destruct (decide (ParentChildIn tg tg' tr)) as [Rel|Unrel]. - - pose proof (seq_always_destruct_last (bor_local_seq_always_rel Rel Ex Ex' Seq)). - tauto. - - pose proof (seq_always_destruct_last (bor_local_seq_always_unrel Unrel Ex Ex' Seq)). - simpl in *. - tauto. -Qed. - -Lemma bor_local_seq_always_backward_reach - {tg tr tr' cids cids' pre evts p0 z} - (Ex : tree_contains tg tr) - (Unq : tree_item_determined tg pre tr) - (Reach : reach p0 (item_perm_at_loc pre z)) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : bor_local_seq {|seq_inv:=fun tr _ => forall post (UnqPost : tree_item_determined tg post tr), reach p0 (item_perm_at_loc post z)|} - tr cids evts tr' cids'. -Proof. - pose proof (bor_local_seq_always_contains Ex Seq) as AllEx. - pose proof (seq_always_merge AllEx (bor_local_seq_always_determined Ex Unq eq_refl AllEx)) as AllExUnq. - eapply seq_always_build_forward; [| |exact AllExUnq]. - + move=> ? Unq'. pose proof (tree_determined_unify Ex Unq Unq'); subst. assumption. - + clear; simpl; move=> ????? Step [Ex [?[Unq _]]] Reach. - move=> ? Unq'. - eapply bor_local_step_preserves_backward_reach; eauto. -Qed. - -Lemma bor_local_seq_always_protected_freeze_like - {tg tr tr' cids cids' pre evts cid z} - (Ex : tree_contains tg tr) - (Unq : tree_item_determined tg pre tr) - (Prot : protector_is_for_call cid (iprot pre)) - (Reach : freeze_like (item_perm_at_loc pre z)) - (Seq : bor_local_seq {|seq_inv:=fun _ cids => call_is_active cid cids|} tr cids evts tr' cids') - : bor_local_seq {|seq_inv:=fun tr _ => forall post (UnqPost : tree_item_determined tg post tr), protector_is_for_call cid (iprot post) /\ freeze_like (item_perm_at_loc post z)|} - tr cids evts tr' cids'. -Proof. - pose proof (bor_local_seq_always_contains Ex (bor_local_seq_forget Seq)) as AllEx. - pose proof (seq_always_merge Seq (seq_always_merge AllEx (bor_local_seq_always_determined Ex Unq eq_refl AllEx))) as AllExUnqProt. - eapply seq_always_build_forward; [| |exact AllExUnqProt]. - + move=> ? Unq'. pose proof (tree_determined_unify Ex Unq Unq'); subst. split; assumption. - + clear; simpl; move=> ???? evt Step [Prot [Ex [? [Unq _]]]] Reach. - move=> ? Unq'. - destruct (Reach _ Unq) as [SameProt FrzLike]. - split. - * pose proof (bor_local_step_preserves_contains Ex Step) as Ex'. - destruct (bor_local_step_preserves_determined_easy Ex Unq Step) as [x [Unqx Protx]]. - pose proof (tree_determined_unify Ex' Unq' Unqx); subst. - destruct evt; rewrite <- Protx; assumption. - * eapply bor_local_step_preserves_protected_freeze_like; eauto. - exists cid; split; assumption. -Qed. - -Lemma bor_local_seq_last_backward_reach - {tg tr tr' cids cids' pre evts p0 z} - (Ex : tree_contains tg tr) - (Unq : tree_item_determined tg pre tr) - (Reach : reach p0 (item_perm_at_loc pre z)) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : forall post (UnqPost : tree_item_determined tg post tr'), reach p0 (item_perm_at_loc post z). -Proof. - pose proof (seq_always_destruct_last (bor_local_seq_always_backward_reach Ex Unq Reach Seq)). - assumption. -Qed. - -Lemma bor_local_seq_last_protected_freeze_like - {tg tr tr' cids cids' pre evts cid z} - (Ex : tree_contains tg tr) - (Unq : tree_item_determined tg pre tr) - (Prot : protector_is_for_call cid (iprot pre)) - (FrzLike : freeze_like (item_perm_at_loc pre z)) - (Seq : bor_local_seq {|seq_inv:=fun _ cids => call_is_active cid cids|} tr cids evts tr' cids') - : forall post (UnqPost : tree_item_determined tg post tr'), protector_is_for_call cid (iprot post) /\ freeze_like (item_perm_at_loc post z). -Proof. - pose proof (seq_always_destruct_last (bor_local_seq_always_protected_freeze_like Ex Unq Prot FrzLike Seq)). - assumption. -Qed. - -Lemma bor_local_seq_always_forward_unreach - {tg tr tr' cids cids' pre evts p0 z} - (Ex : tree_contains tg tr) - (Unq : tree_item_determined tg pre tr) - (Unreach : ~reach (item_perm_at_loc pre z) p0) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : bor_local_seq {|seq_inv:=fun tr _ => forall post (UnqPost : tree_item_determined tg post tr), ~reach (item_perm_at_loc post z) p0|} - tr cids evts tr' cids'. -Proof. - pose proof (bor_local_seq_always_contains Ex Seq) as AllEx. - pose proof (seq_always_merge AllEx (bor_local_seq_always_determined Ex Unq eq_refl AllEx)) as AllExUnq. - eapply seq_always_build_forward; [| |exact AllExUnq]. - + move=> ? Unq'. pose proof (tree_determined_unify Ex Unq Unq'); subst. assumption. - + clear; move=> ????? Step [Ex [?[Unq _]]] Reach. - move=> ? Unq'. - eapply bor_local_step_preserves_forward_unreach; eauto. -Qed. - -Lemma bor_local_seq_last_forward_unreach - {tg tr tr' cids cids' pre evts p0 z} - (Ex : tree_contains tg tr) - (Unq : tree_item_determined tg pre tr) - (Unreach : ~reach (item_perm_at_loc pre z) p0) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : forall post (UnqPost : tree_item_determined tg post tr'), ~reach (item_perm_at_loc post z) p0. -Proof. - pose proof (seq_always_destruct_last (bor_local_seq_always_forward_unreach Ex Unq Unreach Seq)). - assumption. -Qed. - -Lemma bor_local_seq_split - {invariant tr tr' cids cids' l l'} - : bor_local_seq invariant tr cids (l ++ l') tr' cids' - <-> exists tr'' cids'', bor_local_seq invariant tr cids l tr'' cids'' /\ bor_local_seq invariant tr'' cids'' l' tr' cids'. -Proof. - generalize dependent tr. - generalize dependent cids. - induction l as [|?? IHl]; move=> ??. - - simpl; split; intro Hyp. - + eexists. eexists. split; [constructor|assumption]. - all: inversion Hyp; subst; auto. - + destruct Hyp as [?[?[S S']]]. - inversion S; subst. - exact S'. - - simpl; split; intro Hyp. - + inversion Hyp as [|??????? HEAD REST]; subst. - rewrite IHl in REST. - destruct REST as [?[?[S' S'']]]. - eexists. eexists. - split. - * econstructor; [assumption|exact HEAD|exact S']. - * assumption. - + destruct Hyp as [?[?[S S']]]. - inversion S as [|??????? HEAD REST]; subst. - econstructor; [assumption|exact HEAD|]. - rewrite IHl. - eexists. eexists. - split; eassumption. -Qed. - Lemma apply_access_perm_preserves_perminit {pre post kind rel b} (Access : apply_access_perm kind rel b pre = Some post) @@ -864,7 +326,7 @@ Proof. all: intros H H'; inversion H'; inversion H. Qed. - +(** Initialized status is monotonous: an initialized location stays initialized. *) Lemma memory_access_preserves_perminit {access_tag affected_tag pre tr post tr' kind cids range z zpre zpost} (ExAff : tree_contains affected_tag tr) @@ -894,6 +356,7 @@ Proof. all: rewrite Lkup; simpl; try exact Apply. Qed. +(** Furthermore a child access produces an initialized. *) Lemma apply_access_perm_child_produces_perminit {pre post kind b rel} (CHILD : if rel is Child _ then True else False) @@ -940,82 +403,7 @@ Proof. all: simpl; done. Qed. -Lemma bor_local_step_preserves_perminit - {affected_tag tr cids evt tr' cids' pre z zpre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (ItemPre : item_lazy_perm_at_loc pre z = zpre) - (Initialized : initialized zpre = PermInit) - (Step : bor_local_step tr cids evt tr' cids') - : forall post, - tree_item_determined affected_tag post tr' -> - initialized (item_lazy_perm_at_loc post z) = PermInit. -Proof. - move=> post Unq'. - inversion Step as [???? EXISTS_TAG ACC| | |?? tg????? FRESH_CHILD ? RETAG_EFFECT]; subst. - - eapply memory_access_preserves_perminit. - + exact Ex. - + exact Unq. - + exact EXISTS_TAG. - + exact ACC. - + exact Unq'. - + reflexivity. - + reflexivity. - + exact Initialized. - - pose proof (tree_determined_unify Ex Unq Unq'); subst. - assumption. - - pose proof (tree_determined_unify Ex Unq Unq'); subst. - assumption. - - assert (affected_tag ≠tg) as Ne by (intro; subst; contradiction). - pose proof (create_child_preserves_determined _ _ _ _ _ _ _ _ _ _ _ Ne Unq RETAG_EFFECT) as UnqPost. - pose proof (insertion_preserves_tags Ex RETAG_EFFECT) as Ex'. - pose proof (tree_determined_unify Ex' UnqPost Unq'); subst. - assumption. -Qed. - -Lemma bor_local_step_child_produces_perminit - {access_tag affected_tag pre tr tr' kind cids cids' z range} - (ExAff : tree_contains affected_tag tr) - (UnqAff : tree_item_determined affected_tag pre tr) - (Rel : ParentChildIn affected_tag access_tag tr) - (WithinRange : range'_contains range z) - (Step : bor_local_step tr cids (AccessBLEvt kind access_tag range) tr' cids') - : forall post, - tree_item_determined affected_tag post tr' -> - initialized (item_lazy_perm_at_loc post z) = PermInit. -Proof. - inversion Step; subst. - intros. - eapply memory_access_child_produces_perminit. - 1: exact ExAff. - all: eauto. -Qed. - -Lemma bor_local_seq_always_perminit - {affected_tag tr tr' cids cids' evts pre z} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (InitPre : initialized (item_lazy_perm_at_loc pre z) = PermInit) - (Seq : bor_local_seq {|seq_inv:=fun _ _ => True|} tr cids evts tr' cids') - : bor_local_seq - {|seq_inv:=fun tr _ => - forall it, - tree_item_determined affected_tag it tr -> - initialized (item_lazy_perm_at_loc it z) = PermInit|} - tr cids evts tr' cids'. -Proof. - pose proof (bor_local_seq_always_contains Ex Seq) as SeqEx. - pose proof (bor_local_seq_always_determined Ex Unq eq_refl SeqEx) as SeqUnq. - eapply seq_always_build_forward; simpl; [| |exact (seq_always_merge SeqEx SeqUnq)]. - - intros pre' Unq'. pose proof (tree_determined_unify Ex Unq Unq'); subst. - assumption. - - intros ????? Step Inv Init. - simpl in Inv; destruct Inv as [Exi [?[Unqi ?]]]. - eapply bor_local_step_preserves_perminit. - 1: exact Exi. - all: eauto. -Qed. - +(** Protected + initialized prevents loss of [Active]. *) Lemma apply_access_perm_protected_initialized_preserves_active {pre post kind rel} (Access : apply_access_perm kind rel true pre = Some post) @@ -1061,73 +449,6 @@ Proof. - rewrite Spec; tauto. Qed. -Lemma protected_during_step_stays_active - {affected_tag tr cids evt tr' cids' pre z zpre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Prot : protector_is_active (iprot pre) cids) - (ItemPre : item_lazy_perm_at_loc pre z = zpre) - (Init : initialized zpre = PermInit) - (ActPre : perm zpre = Active) - (Step : bor_local_step tr cids evt tr' cids') - : forall post, tree_item_determined affected_tag post tr' -> item_perm_at_loc post z = Active. -Proof. - move=> ? Unq'. - inversion Step as [???? EXISTS_TAG ACC| | |?? tg???? FRESH_CHILD ? RETAG_EFFECT]; subst. - - apply (memory_access_protected_initialized_preserves_active Ex Unq EXISTS_TAG ACC Unq' Prot eq_refl eq_refl Init ActPre). - - rewrite <- (tree_determined_unify Ex Unq Unq'); tauto. - - rewrite <- (tree_determined_unify Ex Unq Unq'); tauto. - - pose proof (bor_local_step_preserves_contains Ex Step) as ExPost'. - pose proof (bor_local_step_preserves_determined_easy Ex Unq Step) as [it' [UnqPost' Eq]]; subst; simpl in UnqPost'. - rewrite <- (tree_determined_unify ExPost' UnqPost' Unq'); tauto. -Qed. - -Lemma protected_during_seq_always_stays_active - {affected_tag tr cids evts tr' cid cids' prot pre z} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Prot : iprot pre = prot) - (Call : protector_is_for_call cid prot) - (StartsActive : item_perm_at_loc pre z = Active) - (Seq : bor_local_seq - {|seq_inv:=fun tr cids => - (forall it, tree_item_determined affected_tag it tr -> initialized (item_lazy_perm_at_loc it z) = PermInit) - /\ call_is_active cid cids|} - tr cids evts tr' cids') - : bor_local_seq - {|seq_inv:=fun tr _ => forall it, tree_item_determined affected_tag it tr -> perm (item_lazy_perm_at_loc it z) = Active|} - tr cids evts tr' cids'. -Proof. - pose proof (bor_local_seq_always_contains Ex (bor_local_seq_forget Seq)) as AllEx. - pose proof (bor_local_seq_always_determined Ex Unq Prot AllEx) as AllUnq. - pose proof (seq_always_merge AllEx (seq_always_merge Seq AllUnq)) as AllExUnqInitProt. - eapply seq_always_build_forward; [| |exact AllExUnqInitProt]. - + move=> it Unq'. pose proof (tree_determined_unify Ex Unq Unq'); subst. assumption. - + generalize Call; clear; simpl; move=> Call ????? Step [Ex [[Init CallAct] [?[Unq ProtEq]]]] Act. - move=> ? Unq'. - subst. - eapply protected_during_step_stays_active; eauto. - eexists; split; eauto. -Qed. - -Lemma protected_during_seq_last_stays_active - {affected_tag tr cids evts tr' cids' cid prot pre z} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Prot : iprot pre = prot) - (Call : protector_is_for_call cid prot) - (StartsActive : item_perm_at_loc pre z = Active) - (Seq : bor_local_seq - {|seq_inv:=fun tr cids => - (forall it, tree_item_determined affected_tag it tr -> initialized (item_lazy_perm_at_loc it z) = PermInit) - /\ call_is_active cid cids|} - tr cids evts tr' cids') - : forall post, tree_item_determined affected_tag post tr' -> perm (item_lazy_perm_at_loc post z) = Active. -Proof. - pose proof (seq_always_destruct_last (protected_during_seq_always_stays_active Ex Unq Prot Call StartsActive Seq)). - assumption. -Qed. - Lemma apply_access_perm_protected_initialized_preserves_nondis {pre post kind rel} (Access : apply_access_perm kind rel true pre = Some post) @@ -1172,89 +493,3 @@ Proof. + assumption. - rewrite Spec; tauto. Qed. - -Lemma protected_during_step_stays_nondis - {affected_tag tr cids evt tr' cids' pre z zpre} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Prot : protector_is_active (iprot pre) cids) - (ItemPre : item_lazy_perm_at_loc pre z = zpre) - (Init : initialized zpre = PermInit) - (NonDisPre : ~reach Disabled (perm zpre)) - (Step : bor_local_step tr cids evt tr' cids') - : forall post, tree_item_determined affected_tag post tr' -> ~reach Disabled (item_perm_at_loc post z). -Proof. - move=> ? Unq'. - inversion Step as [???? EXISTS_TAG ACC| | |?? tg???? FRESH_CHILD ? RETAG_EFFECT]; subst. - - apply (memory_access_protected_initialized_preserves_nondis Ex Unq EXISTS_TAG ACC Unq' Prot eq_refl eq_refl Init NonDisPre). - - rewrite <- (tree_determined_unify Ex Unq Unq'); tauto. - - rewrite <- (tree_determined_unify Ex Unq Unq'); tauto. - - pose proof (bor_local_step_preserves_contains Ex Step) as ExPost'. - pose proof (bor_local_step_preserves_determined_easy Ex Unq Step) as [it' [UnqPost' Eq]]; subst; simpl in UnqPost'. - rewrite <- (tree_determined_unify ExPost' UnqPost' Unq'); tauto. -Qed. - -Lemma protected_during_seq_always_stays_nondis - {affected_tag tr cids evts tr' cid cids' prot pre z} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Prot : iprot pre = prot) - (Call : protector_is_for_call cid prot) - (StartsNonDis : ~reach Disabled (item_perm_at_loc pre z)) - (Seq : bor_local_seq - {|seq_inv:=fun tr cids => - (forall it, tree_item_determined affected_tag it tr -> initialized (item_lazy_perm_at_loc it z) = PermInit) - /\ call_is_active cid cids|} - tr cids evts tr' cids') - : bor_local_seq - {|seq_inv:=fun tr _ => forall it, tree_item_determined affected_tag it tr -> ~reach Disabled (perm (item_lazy_perm_at_loc it z))|} - tr cids evts tr' cids'. -Proof. - pose proof (bor_local_seq_always_contains Ex (bor_local_seq_forget Seq)) as AllEx. - pose proof (bor_local_seq_always_determined Ex Unq Prot AllEx) as AllUnq. - pose proof (seq_always_merge AllEx (seq_always_merge Seq AllUnq)) as AllExUnqInitProt. - eapply seq_always_build_forward; [| |exact AllExUnqInitProt]. - + move=> it Unq'. pose proof (tree_determined_unify Ex Unq Unq'); subst. assumption. - + generalize Call; clear; simpl; move=> Call ????? Step [Ex [[Init CallAct] [?[Unq ProtEq]]]] Act. - move=> ? Unq'. - subst. - eapply protected_during_step_stays_nondis; eauto. - eexists; split; eauto. -Qed. - -Lemma protected_during_seq_last_stays_nondis - {affected_tag tr cids evts tr' cids' cid prot pre z} - (Ex : tree_contains affected_tag tr) - (Unq : tree_item_determined affected_tag pre tr) - (Prot : iprot pre = prot) - (Call : protector_is_for_call cid prot) - (StartsNonDis : ~reach Disabled (item_perm_at_loc pre z)) - (Seq : bor_local_seq - {|seq_inv:=fun tr cids => - (forall it, tree_item_determined affected_tag it tr -> initialized (item_lazy_perm_at_loc it z) = PermInit) - /\ call_is_active cid cids|} - tr cids evts tr' cids') - : forall post, tree_item_determined affected_tag post tr' -> ~reach Disabled (perm (item_lazy_perm_at_loc post z)). -Proof. - pose proof (seq_always_destruct_last (protected_during_seq_always_stays_nondis Ex Unq Prot Call StartsNonDis Seq)). - assumption. -Qed. - -(* For bor_seq - -== Preservation lemmas == -[X] contains -[X] determined (quantified) -[X] reach, unreach -[X] when protected: stays active, stays frozen -[X] stays initialized - -== Lookahead lemmas == -[ ] future EndCall implies call currently active -[ ] future retag implies currently fresh -[ ] future retag implies parent exists - -== Other lemmas == -[X] split/merge list manipulations - -*) diff --git a/theories/tree_borrows/steps_progress.v b/theories/tree_borrows/steps_progress.v index 455b3620788b349ef60647a9115c9d41dd1b56d4..2fca45fb02a394a6fa3773501abffe7e791cbe57 100755 --- a/theories/tree_borrows/steps_progress.v +++ b/theories/tree_borrows/steps_progress.v @@ -1,12 +1,10 @@ -(** This file has been adapted from the Stacked Borrows development, available at - https://gitlab.mpi-sws.org/FP/stacked-borrows -*) +(** Statements of success conditions for borrow steps. + The goal is to be able to prove a [bor_step] statement. *) From simuliris.tree_borrows Require Export steps_wf. From Equations Require Import Equations. From iris.prelude Require Import options. -(* TODO: do we need non-empty condition? ie (sizeof ptr) > 0? *) Lemma alloc_base_step P σ sz : state_wf σ -> (sz > 0)%nat -> @@ -30,7 +28,7 @@ Proof. exact Dom. Qed. - +(* Basically, [tree_apply_access] works iff every node accepts the inner function being applied *) Lemma apply_access_success_condition tr cids access_tag range fn : every_node (fun it => is_Some (item_apply_access fn cids (rel_dec tr access_tag (itag it)) range it)) tr <-> is_Some (tree_apply_access fn cids access_tag range tr). @@ -41,7 +39,6 @@ Proof. tauto. Qed. - Lemma apply_access_fail_condition tr cids access_tag range fn : exists_node (fun it => item_apply_access fn cids (rel_dec tr access_tag (itag it)) range it = None) tr <-> tree_apply_access fn cids access_tag range tr = None. @@ -52,6 +49,7 @@ Proof. tauto. Qed. +(* [mem_apply_range'] succeeds iff every offset succeeds. *) Lemma mem_apply_range'_success_condition {X} (map : gmap Z X) fn range : (forall l, range'_contains range l -> is_Some (fn (map !! l))) <-> is_Some (mem_apply_range' fn range map). @@ -180,46 +178,6 @@ Proof. destruct (ProtVulnerable ltac:(reflexivity)); discriminate. Qed. - - -(* -Lemma dealloc1_progress stk bor cids - (PR: Forall (λ it, ¬ is_active_protector cids it) stk) - (BOR: ∃ it, it ∈ stk ∧ it.(tg) = bor ∧ - it.(perm) ≠Disabled ∧ it.(perm) ≠SharedReadOnly) : - is_Some (dealloc1 stk bor cids). -Proof. - rewrite /dealloc1. - destruct (find_granting_is_Some stk AccessWrite bor) as [? Eq]; [naive_solver|]. - rewrite Eq /find_top_active_protector list_find_None_inv; - [by eexists|done]. -Qed. - -Lemma for_each_is_Some α l (n: nat) b f : - (∀ m : Z, 0 ≤ m ∧ m < n → l +â‚— m ∈ dom α) → - (∀ (m: nat) stk, (m < n)%nat → α !! (l +â‚— m) = Some stk → is_Some (f stk)) → - is_Some (for_each α l n b f). -Proof. - revert α. induction n as [|n IHn]; intros α IN Hf; [by eexists|]. simpl. - assert (is_Some (α !! (l +â‚— n))) as [stk Eq]. - { apply (elem_of_dom (D:=gset loc)), IN. by lia. } - rewrite Eq /=. destruct (Hf n stk) as [stk' Eq']; [lia|done|]. - rewrite Eq' /=. destruct b; apply IHn. - - intros. apply elem_of_dom. rewrite lookup_delete_ne. - + apply (elem_of_dom (D:=gset loc)), IN. lia. - + move => /shift_loc_inj. lia. - - intros ???. rewrite lookup_delete_ne. - + apply Hf. lia. - + move => /shift_loc_inj. lia. - - intros. apply elem_of_dom. rewrite lookup_insert_ne. - + apply (elem_of_dom (D:=gset loc)), IN. lia. - + move => /shift_loc_inj. lia. - - intros ???. rewrite lookup_insert_ne. - + apply Hf. lia. - + move => /shift_loc_inj. lia. -Qed. -*) - (* For a protector to allow deallocation it must be weak or inactive *) Definition item_deallocateable_protector cids (it: item) := match it.(iprot) with @@ -227,47 +185,6 @@ Definition item_deallocateable_protector cids (it: item) := | _ => True end. -(* Deallocation progress is going to be a bit more tricky because we need the success of the write *) -(* -Lemma memory_deallocated_progress α cids l bor (n: nat) : - (∀ m : Z, 0 ≤ m ∧ m < n → l +â‚— m ∈ dom α) → - (∀ (m: nat) stk, (m < n)%nat → α !! (l +â‚— m) = Some stk → - (∃ it, it ∈ stk ∧ it.(itag) = bor ∧ - it.(perm) ≠Disabled ∧ it.(perm) ≠SharedReadOnly) ∧ - ∀ it, it ∈ stk → item_inactive_protector cids it) → - is_Some (memory_deallocated α cids l bor n). -Proof. - intros IN IT. apply for_each_is_Some; [done|]. - intros m stk Lt Eq. destruct (IT _ _ Lt Eq) as [In PR]. - destruct (dealloc1_progress stk bor cids) as [? Eq1]; - [|done|rewrite Eq1; by eexists]. - apply Forall_forall. move => it /PR. - rewrite /item_inactive_protector /is_active_protector /is_active. - case protector; naive_solver. -Qed. -*) -(* -Lemma memory_deallocate_progress (σ: state) l tg (sz:nat) (WF: state_wf σ) : - (∀ m : Z, is_Some (σ.(shp) !! (l +â‚— m)) ↔ 0 ≤ m ∧ m < sz) → - (sz > 0)%nat → - trees_contain tg (strs σ) l.1 → - is_Some (apply_within_trees (memory_deallocate σ.(scs) tg (l.2, sz)) l.1 σ.(strs)). -Proof. - intros Hfoo Hbar Hcont. - eexists. Locate trees_contain. unfold trees_contain in Hcont. unfold trees_at_block in Hcont. - destruct (strs σ !! l.1) as [tr|] eqn:Heqtr; last done. - rewrite /apply_within_trees /memory_deallocate Heqtr /=. - unfold tree_apply_access. - Print join_nodes. - Print map_nodes. - Search join_nodes. - simpl. - Print apply_within_trees. - Print memory_deallocate. - Print tree_apply_access. - Print item_apply_access. - Print memory_deallocate. -*) Lemma dealloc_base_step' P (σ: state) l tg (sz:nat) α' (WF: state_wf σ) : (∀ m : Z, is_Some (σ.(shp) !! (l +â‚— m)) ↔ 0 ≤ m ∧ m < sz) → (sz > 0)%nat → @@ -279,25 +196,6 @@ Proof. intros Hdom Hpos Hcont Happly. destruct l as [blk off]. econstructor; econstructor; auto. Qed. -(* -Lemma dealloc_base_step P (σ: state) T l bor - (WF: state_wf σ) - (BLK: ∀ m : Z, l +â‚— m ∈ dom σ.(shp) ↔ 0 ≤ m ∧ m < tsize T) - (BOR: ∀ (n: nat) stk, (n < tsize T)%nat → - σ.(sst) !! (l +â‚— n) = Some stk → - (∃ it, it ∈ stk ∧ it.(tg) = bor ∧ - it.(perm) ≠Disabled ∧ it.(perm) ≠SharedReadOnly) ∧ - ∀ it, it ∈ stk → item_inactive_protector σ.(scs) it) : - ∃ σ', - base_step P (Free (Place l bor T)) σ #[☠] σ' []. -Proof. - destruct (memory_deallocated_progress σ.(sst) σ.(scs) l bor (tsize T)) - as [α' Eq']; [|done|]. - - intros. rewrite -(state_wf_dom _ WF). by apply BLK. - - eexists. econstructor; econstructor; [|done]. - intros. by rewrite -(elem_of_dom (D:= gset loc) σ.(shp)). -Qed. -*) (* Success of `read_mem` on the heap is unchanged. *) Lemma read_mem_is_Some' l n h : @@ -362,147 +260,8 @@ Proof. rewrite -Hs; last lia. rewrite -Hv'; last lia. intros -> [= ->]. done. Qed. -(* -Lemma replace_check'_is_Some cids acc stk : - (∀ it, it ∈ stk → it.(perm) = Unique → item_inactive_protector cids it) → - is_Some (replace_check' cids acc stk). -Proof. - revert acc. induction stk as [|si stk IH]; intros acc PR; simpl; [by eexists|]. - case decide => EqU; last by (apply IH; set_solver). - rewrite (Is_true_eq_true (check_protector cids si)); first by (apply IH; set_solver). - have IN: si ∈ si :: stk by set_solver. apply PR in IN; [|done]. - move : IN. rewrite /check_protector /item_inactive_protector. - case si.(protector) => [? /negb_prop_intro|//]. by case is_active. -Qed. - -Lemma replace_check_is_Some cids stk : - (∀ it, it ∈ stk → it.(perm) = Unique → item_inactive_protector cids it) → - is_Some (replace_check cids stk). -Proof. move => /replace_check'_is_Some IS. by apply IS. Qed. - -*) - - -(* -Definition access1_read_pre cids (stk: stack) (bor: tag) := - ∃ (i: nat) it, stk !! i = Some it ∧ it.(tg) = bor ∧ it.(perm) ≠Disabled ∧ - ∀ (j: nat) jt, (j < i)%nat → stk !! j = Some jt → - (jt.(perm) = Disabled ∨ jt.(tg) ≠bor) ∧ - match jt.(perm) with - | Unique => item_inactive_protector cids jt - | _ => True - end. - -Definition access1_write_pre cids (stk: stack) (bor: tag) := - ∃ (i: nat) it, stk !! i = Some it ∧ it.(perm) ≠Disabled ∧ - it.(perm) ≠SharedReadOnly ∧ it.(tg) = bor ∧ - ∀ (j: nat) jt, (j < i)%nat → stk !! j = Some jt → - (jt.(perm) = Disabled ∨ jt.(perm) = SharedReadOnly ∨ jt.(tg) ≠bor) ∧ - match find_first_write_incompatible (take i stk) it.(perm) with - | Some idx => - if decide (j < idx)%nat then - (* Note: if a Disabled item is already in the stack, then its protector - must have been inactive since its insertion, so this condition is - unneccessary. *) - item_inactive_protector cids jt - else True - | _ => True - end. - *) - Definition is_write (access: access_kind) : bool := match access with AccessWrite => true | _ => false end. -(* -Definition access1_pre - cids (stk: stack) (access: access_kind) (bor: tag) := - ∃ (i: nat) it, stk !! i = Some it ∧ it.(perm) ≠Disabled ∧ - (is_write access → it.(perm) ≠SharedReadOnly) ∧ it.(tg) = bor ∧ - ∀ (j: nat) jt, (j < i)%nat → stk !! j = Some jt → - (jt.(perm) = Disabled ∨ - (if is_write access then jt.(perm) = SharedReadOnly ∨ jt.(tg) ≠bor - else jt.(tg) ≠bor)) ∧ - if is_write access then - match find_first_write_incompatible (take i stk) it.(perm) with - | Some idx => - if decide (j < idx)%nat then - (* Note: if a Disabled item is already in the stack, then its protector - must have been inactive since its insertion, so this condition is - unneccessary. *) - item_inactive_protector cids jt - else True - | _ => True - end - else - match jt.(perm) with - | Unique => item_inactive_protector cids jt - | _ => True - end. - *) - -(* -Lemma access1_is_Some cids stk kind bor - (BOR: access1_pre cids stk kind bor) : - is_Some (access1 stk kind bor cids). -Proof. - destruct BOR as (i & it & Eqi & ND & IW & Eqit & Lti). - rewrite /access1 /find_granting. - rewrite (_: list_find (matched_grant kind bor) stk = Some (i, it)); last first. - { apply list_find_Some_not_earlier. split; last split; [done|..]. - - split; [|done]. - destruct kind; [by apply grants_access_all|by apply grants_write_all, IW]. - - intros ?? Lt Eq GR. destruct (Lti _ _ Lt Eq) as [[Eq1|NEq1] NEq2]. - { move : GR. rewrite /matched_grant Eq1 /=. naive_solver. } - destruct kind; [by apply NEq1, GR|]. destruct NEq1 as [OR|OR]. - + move : GR. rewrite /matched_grant OR /=. naive_solver. - + by apply OR, GR. } simpl. - have ?: (i ≤ length stk)%nat. { by eapply Nat.lt_le_incl, lookup_lt_Some. } - destruct kind. - - destruct (replace_check_is_Some cids (take i stk)) as [? Eq2]; - [|rewrite Eq2 /=; by eexists]. - intros jt [j Eqj]%elem_of_list_lookup_1 IU. - have ?: (j < i)%nat. - { rewrite -(length_take_le stk i); [|done]. by eapply lookup_lt_Some. } - destruct (Lti j jt) as [Eq1 PR]; [done|..]. - + symmetry. by rewrite -Eqj lookup_take. - + move : PR. by rewrite /= IU. - - destruct (find_first_write_incompatible_is_Some (take i stk) it.(perm)) - as [idx Eqx]; [done|by apply IW|]. rewrite Eqx /=. - destruct (remove_check_is_Some cids (take i stk) idx) as [stk' Eq']; - [..|rewrite Eq'; by eexists]. - + move : Eqx. apply find_first_write_incompatible_length. - + intros j jt Lt Eqj. - have ?: (j < i)%nat. - { rewrite -(length_take_le stk i); [|done]. by eapply lookup_lt_Some. } - destruct (Lti j jt) as [Eq1 PR]; [done|..]. - * symmetry. by rewrite -Eqj lookup_take. - * move : PR. by rewrite /= Eqx decide_True. -Qed. - -Lemma access1_read_is_Some cids stk bor - (BOR: access1_read_pre cids stk bor) : - is_Some (access1 stk AccessRead bor cids). -Proof. - destruct BOR as (i & it & Eqi & Eqit & ND & Lti). - apply access1_is_Some. exists i, it. do 4 (split; [done|]). - intros j jt Lt Eq. by destruct (Lti _ _ Lt Eq). -Qed. - *) - -(* -Lemma memory_read_is_Some α cids l bor (n: nat) : - (∀ m, (m < n)%nat → l +â‚— m ∈ dom α) → - (∀ (m: nat) stk, (m < n)%nat → - α !! (l +â‚— m) = Some stk → access1_read_pre cids stk bor) → - is_Some (memory_read α cids l bor n). -Proof. - intros IN STK. apply for_each_is_Some. - - intros m []. rewrite -(Z2Nat.id m); [|done]. apply IN. - rewrite -(Nat2Z.id n) -Z2Nat.inj_lt; [done..|lia]. - - intros m stk Lt Eq. - specialize (STK _ _ Lt Eq). - destruct (access1_read_is_Some _ _ _ STK) as [? Eq2]. rewrite Eq2. by eexists. -Qed. - *) Lemma apply_within_trees_unchanged fn blk trs trs' : (∀ tr, trs !! blk = Some tr → fn tr = Some tr) → @@ -528,59 +287,7 @@ Proof. intros tr Htr. simpl in Htr|-*. eapply (zero_sized_memory_access_unchanged false). - do 2 econstructor. all: eauto. Qed. -(* TODO remove? -Lemma copy_base_step P (σ: state) l bor T - (WF: state_wf σ) - (BLK: ∀ n, (n < tsize T)%nat → l +â‚— n ∈ dom σ.(shp)) - (BOR: ∀ m stk, (m < tsize T)%nat → σ.(sst) !! (l +â‚— m) = Some stk → - access1_read_pre σ.(scs) stk bor) : - ∃ v α, - read_mem l (tsize T) σ.(shp) = Some v ∧ - memory_read σ.(sst) σ.(scs) l bor (tsize T) = Some α ∧ - let σ' := mkState σ.(shp) α σ.(scs) σ.(snp) σ.(snc) in - base_step P (Copy (Place l bor T)) σ (Val v) σ' []. -Proof. - destruct (read_mem_is_Some _ _ _ BLK) as [v RM]. - destruct (memory_read_is_Some σ.(sst) σ.(scs) l bor (tsize T));[|done|]. - { move => ? /BLK. by rewrite (state_wf_dom _ WF). } - do 2 eexists. do 2 (split; [done|]). intros σ'. - eapply copy_base_step'; eauto. -Qed. *) -Lemma failed_copy_base_step' P (σ: state) l tg sz (WF: state_wf σ) : - trees_contain tg σ.(strs) l.1 → - apply_within_trees (memory_access AccessRead σ.(scs) tg (l.2, sz)) l.1 σ.(strs) = None → - is_Some (read_mem l sz σ.(shp)) → - base_step P (Copy (Place l tg sz)) σ (Val $ replicate sz ScPoison) σ []. -Proof. - intros TC Happly. destruct l, σ. do 2 econstructor; by eauto. -Qed. - -(* - -Lemma access1_write_is_Some cids stk bor - (BOR: access1_write_pre cids stk bor) : - is_Some (access1 stk AccessWrite bor cids). -Proof. - destruct BOR as (i & it & Eqi & ND & Neqi & Eqit & Lti). - apply access1_is_Some. exists i, it. do 4 (split; [done|]). - intros j jt Lt Eq. by destruct (Lti _ _ Lt Eq). -Qed. - -Lemma memory_written_is_Some α cids l bor (n: nat) : - (∀ m, (m < n)%nat → l +â‚— m ∈ dom α) → - (∀ (m: nat) stk, (m < n)%nat → - α !! (l +â‚— m) = Some stk → access1_write_pre cids stk bor) → - is_Some (memory_written α cids l bor n). -Proof. - intros IN STK. apply for_each_is_Some. - - intros m []. rewrite -(Z2Nat.id m); [|done]. apply IN. - rewrite -(Nat2Z.id n) -Z2Nat.inj_lt; [done..|lia]. - - intros m stk Lt Eq. - specialize (STK _ _ Lt Eq). - destruct (access1_write_is_Some _ _ _ STK) as [? Eq2]. rewrite Eq2. by eexists. -Qed. -*) Lemma write_base_step' P (σ: state) l bor sz v trs' (LEN: length v = sz) (BLK: ∀ n, (n < sz)%nat → l +â‚— n ∈ dom σ.(shp)) @@ -597,25 +304,6 @@ Proof. - econstructor 2; econstructor; eauto. by rewrite LEN. Qed. -(* -Lemma write_base_step P (σ: state) l bor T v - (WF: state_wf σ) - (LEN: length v = tsize T) - (*(LOCVAL: v <<t σ.(snp))*) - (BLK: ∀ n, (n < tsize T)%nat → l +â‚— n ∈ dom σ.(shp)) - (STK: ∀ m stk, (m < tsize T)%nat → σ.(sst) !! (l +â‚— m) = Some stk → - access1_write_pre σ.(scs) stk bor) : - ∃ α, - memory_written σ.(sst) σ.(scs) l bor (tsize T) = Some α ∧ - let σ' := mkState (write_mem l v σ.(shp)) α σ.(scs) σ.(snp) σ.(snc) in - base_step P (Write (Place l bor T) (Val v)) σ #[☠] σ' []. -Proof. - destruct (memory_written_is_Some σ.(sst) σ.(scs) l bor (tsize T)); [|done|]. - { move => ? /BLK. by rewrite (state_wf_dom _ WF). } - eexists. split; [done|]. by eapply write_base_step'. -Qed. - *) - Lemma call_base_step P σ name e r fn : P !! name = Some fn → to_result e = Some r → @@ -636,363 +324,3 @@ Lemma end_call_base_step P (σ: state) trs' c : base_step P (EndCall #[ScCallId c]) σ #[☠] σ' []. Proof. intros ??. by econstructor; econstructor. Qed. -(* - -Lemma unsafe_action_is_Some_weak {A} (GI: A → nat → Prop) - (f: A → _ → nat → _ → _) a l last cur_dist n - (HF: ∀ a i j b, (last ≤ i ≤ j ∧ j ≤ last + cur_dist + n)%nat → GI a i → - ∃ a', f a (l +â‚— i) (Z.to_nat (j - i)) b = Some a' ∧ GI a' j) : - GI a last → ∃ a' last' cur_dist', - unsafe_action f a l last cur_dist n = Some (a', (last', cur_dist')) ∧ GI a' last'. -Proof. - intros HI. rewrite /unsafe_action. - destruct (HF a last (last + cur_dist)%nat true) as [a' Eq1]; [lia|done|]. - move : Eq1. - rewrite (_: Z.to_nat (Z.of_nat (last + cur_dist) - Z.of_nat last) = cur_dist); - last by rewrite Nat2Z.inj_add Z.add_simpl_l Nat2Z.id. - move => [-> HI'] /=. - destruct (HF a' (last + cur_dist)%nat (last + cur_dist + n)%nat false) - as [? [Eq2 HI2]]; [lia|done|]. - move : Eq2. - rewrite (_: Z.to_nat (Z.of_nat (last + cur_dist + n) - - Z.of_nat (last + cur_dist)) = n); - last by rewrite Nat2Z.inj_add Z.add_simpl_l Nat2Z.id. - move => -> /=. by do 3 eexists. -Qed. - - -Lemma visit_freeze_sensitive'_is_Some {A} (GI: A → nat → Prop) - l (f: A → _ → nat → _ → _) a (last cur_dist: nat) T - (HF: ∀ a i j b, (last ≤ i ≤ j ∧ j ≤ last + cur_dist + tsize T)%nat → GI a i → - ∃ a', f a (l +â‚— i) (Z.to_nat (j - i)) b = Some a' ∧ GI a' j) : - GI a last → ∃ a' last' cur_dist', - visit_freeze_sensitive' l f a last cur_dist T = Some (a', (last', cur_dist')) ∧ - GI a' last'. -Proof. - revert HF. - apply (visit_freeze_sensitive'_elim - (* general goal P *) - (λ l f a last cur_dist T oalc, - (∀ a i j b,(last ≤ i ≤ j ∧ j ≤ last + cur_dist + tsize T)%nat → GI a i → - ∃ a', f a (l +â‚— i) (Z.to_nat (j - i)) b = Some a' ∧ GI a' j) → - GI a last → ∃ a' last' cur', oalc = Some (a', (last', cur')) ∧ GI a' last') - (λ l f _ _ _ _ a last cur_dist Ts oalc, - (∀ a i j b, (last ≤ i ≤ j ∧ j ≤ last + cur_dist + tsize (Product Ts))%nat → - GI a i → ∃ a', f a (l +â‚— i) (Z.to_nat (j - i)) b = Some a' ∧ GI a' j) → - GI a last → ∃ a' last' cur', oalc = Some (a', (last', cur')) ∧ GI a' last')). - - naive_solver. - - naive_solver. - - clear. intros ?????? HF. by apply unsafe_action_is_Some_weak. - - clear. intros l f a last cur_dist T HF. - case is_freeze; [by do 3 eexists|]. by apply unsafe_action_is_Some_weak. - - clear. intros l f a last cur_dist Ts IH Hf HI. - case is_freeze; [intros; simplify_eq/=; exists a, last; by eexists|by apply IH]. - - clear. intros l f a last cur_dist T HF. - case is_freeze; [by do 3 eexists|]. by apply unsafe_action_is_Some_weak. - - naive_solver. - - clear. - intros l f a last cur_dist Ts a1 last1 cur_dist1 T1 Ts1 IH1 IH2 HF HI. - destruct IH2 as (a2 & last2 & cur_dist2 & Eq1 & HI2); [..|done|]. - { intros ???? [? Le]. apply HF. split; [done|]. clear -Le. - rewrite tsize_product_cons. by lia. } - destruct (visit_freeze_sensitive'_offsets _ _ _ _ _ _ _ _ _ Eq1) - as [LeO EqO]. - rewrite Eq1 /=. apply (IH1 (a2, (last2,cur_dist2))); [..|done]. - intros a' i j b. cbn -[tsize]. intros Lej. apply HF. - clear -LeO EqO Lej. destruct Lej as [[Le2 Lei] Lej]. - split; [lia|]. move : Lej. rewrite EqO tsize_product_cons. lia. -Qed. - -Lemma visit_freeze_sensitive_is_Some' {A} (GI: A → nat → Prop) - l (f: A → _ → nat → _ → _) a T - (HF: ∀ a i j b, (i ≤ j ∧ j ≤ tsize T)%nat → GI a i → - ∃ a', f a (l +â‚— i) (Z.to_nat (j - i)) b = Some a' ∧ GI a' j) : - GI a O → ∃ a', visit_freeze_sensitive l T f a = Some a' ∧ GI a' (tsize T). -Proof. - intros HI. rewrite /visit_freeze_sensitive. - destruct (visit_freeze_sensitive'_is_Some GI l f a O O T) - as (a1 & l1 & c1 & Eq1 & HI1); [|done|]. - { rewrite 2!Nat.add_0_l. intros ???? [[??]?]. by apply HF. } - rewrite Eq1 -(Nat.add_sub c1 l1) -(Nat2Z.id (c1 + l1 - l1)) - Nat2Z.inj_sub; [|lia]. - move : Eq1. intros [? Eq]%visit_freeze_sensitive'_offsets. - destruct (HF a1 l1 (c1 + l1)%nat true) as (a2 & Eq2 & HI2); [|done|]. - { split; [lia|]. move : Eq. rewrite 2!Nat.add_0_l. lia. } - exists a2. split; [done|]. - move : Eq. by rewrite 2!Nat.add_0_l Nat.add_comm => [<-]. -Qed. - -Lemma visit_freeze_sensitive_is_Some'_2 {A} (GI: A → nat → Prop) - l (f: A → _ → nat → _ → _) a T - (HF: ∀ a i j b, (i ≤ j ∧ j ≤ tsize T)%nat → GI a i → - ∃ a', f a (l +â‚— i) (Z.to_nat (j - i)) b = Some a' ∧ GI a' j) : - GI a O → is_Some (visit_freeze_sensitive l T f a). -Proof. - intros HI. destruct (visit_freeze_sensitive_is_Some' GI l f a T) - as [a' [Eq _]]; [done..|by eexists]. -Qed. - -Lemma visit_freeze_sensitive_is_Some {A} - l (f: A → _ → nat → _ → _) a T - (HF: ∀ a i j b, (i ≤ j ∧ j ≤ tsize T)%nat → - is_Some (f a (l +â‚— i) (Z.to_nat (j - i)) b)) : - is_Some (visit_freeze_sensitive l T f a). -Proof. - destruct (visit_freeze_sensitive_is_Some' (λ _ _, True) l f a T) - as [a' [Eq _]]; [|done..|by eexists]. - intros a1 i j b Le _. destruct (HF a1 i j b Le). by eexists. -Qed. - -Lemma access1_find_granting_agree stk kind bor cids i1 i2 pm1 stk2: - find_granting stk kind bor = Some (i1, pm1) → - access1 stk kind bor cids = Some (i2, stk2) → - i1 = i2. -Proof. - intros FI. rewrite /access1 FI /=. - destruct kind. - - case replace_check => [? /= ?|//]. by simplify_eq/=. - - case find_first_write_incompatible => [? /=|//]. - case remove_check => [? /= ?|//]. by simplify_eq/=. -Qed. - -Lemma find_granting_write stk bor i pi: - find_granting stk AccessWrite bor = Some (i, pi) → - pi ≠Disabled ∧ pi ≠SharedReadOnly. -Proof. - move => /fmap_Some [[??] /= [IS ?]]. simplify_eq/=. - apply list_find_Some in IS as (? & [IS ?] & ?). - move : IS. rewrite /grants. case perm; naive_solver. -Qed. - -(* The precondition `access1_pre` is too strong for the SharedReadWrite case: - we only need a granting item for that case, we don't need the access check. *) -Lemma grant_is_Some stk old new cids : - let access := - if grants new.(perm) AccessWrite then AccessWrite else AccessRead in - access1_pre cids stk access old → - is_Some (grant stk old new cids). -Proof. - intros access ACC. rewrite /grant. - destruct (find_granting_is_Some stk access old) as [[i pi] Eqi]. - { destruct ACC as (i & it & Eqi & ND & NEq & Eqt & Lt). - exists it. split; [by eapply elem_of_list_lookup_2|]. - do 2 (split; [done|]). intros Eqa. apply NEq. by rewrite Eqa. } - rewrite Eqi. cbn -[item_insert_dedup]. - destruct (access1_is_Some _ _ _ _ ACC) as [[i' stk'] Eq]. - rewrite Eq. cbn -[item_insert_dedup]. - destruct new.(perm); try by eexists. - apply find_granting_write in Eqi as []. - destruct (find_first_write_incompatible_is_Some (take i stk) pi) as [? Eq2]; - [done..|rewrite Eq2; by eexists]. -Qed. - -Lemma reborrowN_is_Some α cids l n old new pm protector - (BLK: ∀ m, (m < n)%nat → l +â‚— m ∈ dom α): - let access := if grants pm AccessWrite then AccessWrite else AccessRead in - (∀ (m: nat) stk, (m < n)%nat → α !! (l +â‚— m) = Some stk → - access1_pre cids stk access old) → - is_Some (reborrowN α cids l n old new pm protector). -Proof. - intros access STK. - rewrite /reborrowN. apply for_each_is_Some. - - intros m []. rewrite -(Z2Nat.id m); [|done]. apply BLK. - rewrite -(Nat2Z.id n) -Z2Nat.inj_lt; [done..|lia]. - - intros m stk Lt Eq. apply grant_is_Some. by apply (STK _ _ Lt Eq). -Qed. - -Lemma reborrowN_lookup (α1 α2 : stacks) cids l n old new pm protector - (EQB : reborrowN α1 cids l n old new pm protector = Some α2) : - (∀ m, (n ≤ m)%nat → α2 !! (l +â‚— m) = α1 !! (l +â‚— m)) ∧ - (∀ m stk, (m < n)%nat → α1 !! (l +â‚— m) = Some stk → - ∃ stk', α2 !! (l +â‚— m) = Some stk' ∧ - let item := mkItem pm new protector in - grant stk old item cids = Some stk') ∧ - (∀ m stk', (m < n)%nat → α2 !! (l +â‚— m) = Some stk' → - ∃ stk, α1 !! (l +â‚— m) = Some stk ∧ - let item := mkItem pm new protector in - grant stk old item cids = Some stk'). -Proof. - destruct (for_each_lookup _ _ _ _ _ EQB) as [HL1 [HL2 HL3]]. split; last split. - - intros m Ge. apply HL3. intros i Lt Eq%shift_loc_inj. subst. lia. - - by apply HL1. - - by apply HL2. -Qed. - -Lemma visit_freeze_sensitive'_is_freeze {A} - l (f: A → _ → nat → _ → _) a (last cur_dist: nat) T : - is_freeze T → - visit_freeze_sensitive' l f a last cur_dist T - = Some (a, (last, (cur_dist + tsize T)%nat)). -Proof. - apply (visit_freeze_sensitive'_elim - (* general goal P *) - (λ l f a last cur_dist T oalc, - is_freeze T → oalc = Some (a, (last, (cur_dist + tsize T)%nat))) - (λ l f _ _ _ _ a last cur_dist Ts oalc, - is_freeze (Product Ts) → - oalc = Some (a, (last, (cur_dist + tsize (Product Ts))%nat)))). - - done. - - clear. intros ??????? _. by rewrite /= Nat.add_1_r. - - done. - - clear. intros ??????. by move => /Is_true_eq_true ->. - - clear. intros ?????? _. by move => /Is_true_eq_true ->. - - clear. intros ??????. by move => /Is_true_eq_true ->. - - clear. intros _ _ _ _ _ _ ??? _. by rewrite /= Nat.add_0_r. - - clear. intros l f a last cur_dist Ts a' l1 c1 T Ts' IH1 IH2 FRZ. - rewrite IH2; first rewrite /= (IH1 (a', (l1, c1 + tsize T)%nat)). - + simpl. do 3 f_equal. change (tsize T) with (0 + tsize T)%nat. - rewrite -(foldl_fmap_shift_init _ (λ n, n + tsize T)%nat); - [by lia|intros ?? _; by lia]. - + by eapply is_freeze_cons_product_inv. - + by eapply is_freeze_cons_product_inv. -Qed. - -Lemma visit_freeze_sensitive_is_freeze {A} - l (f: A → _ → nat → _ → _) a T : - is_freeze T → visit_freeze_sensitive l T f a = f a l (tsize T) true. -Proof. - intros FRZ. rewrite /visit_freeze_sensitive visit_freeze_sensitive'_is_freeze; - [by rewrite shift_loc_0_nat Nat.add_0_l|done]. -Qed. - -Lemma reborrow_is_freeze_is_Some α cids l old T kind new prot - (BLK: ∀ m, (m < tsize T)%nat → l +â‚— m ∈ dom α) - (FRZ: is_freeze T) - (STK: ∀ m stk, (m < tsize T)%nat → α !! (l +â‚— m) = Some stk → - let access := match kind with - | SharedRef | RawRef false => AccessRead - | _ => AccessWrite - end in access1_pre cids stk access old) : - is_Some (reborrow α cids l old T kind new prot). -Proof. - rewrite /reborrow. destruct kind as [[]| |[]]. - - by apply reborrowN_is_Some. - - by apply reborrowN_is_Some. - - rewrite visit_freeze_sensitive_is_freeze //. by apply reborrowN_is_Some. - - by apply reborrowN_is_Some. - - rewrite visit_freeze_sensitive_is_freeze //. by apply reborrowN_is_Some. -Qed. - -Lemma reborrow_is_freeze_lookup α cids l old T kind new prot α' - (FRZ: is_freeze T) : - reborrow α cids l old T kind new prot = Some α' → - ∀ m stk', (m < tsize T)%nat → α' !! (l +â‚— m) = Some stk' → - ∃ stk, α !! (l +â‚— m) = Some stk ∧ - let pm := match kind with - | SharedRef | RawRef false => SharedReadOnly - | UniqueRef false => Unique - | UniqueRef true | RawRef true => SharedReadWrite - end in - let item := mkItem pm new prot in - grant stk old item cids = Some stk'. -Proof. - rewrite /reborrow. destruct kind as [[]| |[]]; intros EQB m stk' Lt Eq'. - - apply reborrowN_lookup in EQB as [_ [_ HL]]. by apply HL. - - apply reborrowN_lookup in EQB as [_ [_ HL]]. by apply HL. - - move : EQB. rewrite visit_freeze_sensitive_is_freeze; [|done]. - move => /reborrowN_lookup [_ [_ HL]]. by apply HL. - - apply reborrowN_lookup in EQB as [_ [_ HL]]. by apply HL. - - move : EQB. rewrite visit_freeze_sensitive_is_freeze; [|done]. - move => /reborrowN_lookup [_ [_ HL]]. by apply HL. -Qed. - - -Lemma retag_ref_is_freeze_is_Some α cids nxtp l old T kind prot - (BLK: ∀ n, (n < tsize T)%nat → l +â‚— n ∈ dom α) - (FRZ: is_freeze T) - (STK: ∀ m stk, (m < tsize T)%nat → α !! (l +â‚— m) = Some stk → - let access := match kind with - | SharedRef | RawRef false => AccessRead - | _ => AccessWrite - end in access1_pre cids stk access old) : - is_Some (retag_ref α cids nxtp l old T kind prot). -Proof. - rewrite /retag_ref. destruct (tsize T) as [|sT] eqn:Eqs; [by eexists|]. - set new := match kind with - | RawRef _ => Untagged - | _ => Tagged nxtp - end. - destruct (reborrow_is_freeze_is_Some α cids l old T kind new prot) - as [α1 Eq1]; [by rewrite Eqs|..|done| |]. - { intros m stk Lt. apply STK. by rewrite -Eqs. } - rewrite Eq1 /=. by eexists. -Qed. - -Definition valid_protector rkind (cids: call_id_set) c := - match rkind with | FnEntry => c ∈ cids | _ => True end. -Definition pointer_kind_access pk := - match pk with - | RefPtr Mutable | RawPtr Mutable | BoxPtr => AccessWrite - | _ => AccessRead - end. -Definition valid_block (α: stacks) cids (l: loc) (tg: tag) pk T := - is_freeze T ∧ - (∀ m, (m < tsize T)%nat → l +â‚— m ∈ dom α ∧ ∃ stk, - α !! (l +â‚— m) = Some stk ∧ access1_pre cids stk (pointer_kind_access pk) tg). - -Lemma retag_is_freeze_is_Some α nxtp cids c l otg kind pk T - (LOC: valid_block α cids l otg pk T) : - is_Some (retag α nxtp cids c l otg kind pk T). -Proof. - destruct LOC as (FRZ & EQD). - destruct pk as [[]|mut|]; simpl. - - destruct (retag_ref_is_freeze_is_Some α cids nxtp l otg T - (UniqueRef (is_two_phase kind)) (adding_protector kind c)) - as [bac Eq]; [by apply EQD|done..| |by eexists]. - simpl. clear -EQD. intros m stk Lt Eq. - destruct (EQD _ Lt) as [_ [stk' [Eq' ?]]]. by simplify_eq/=. - - destruct (retag_ref_is_freeze_is_Some α cids nxtp l otg T SharedRef - (adding_protector kind c)) - as [bac Eq]; [by apply EQD|done..| |by eexists]. - simpl. clear -EQD. intros m stk Lt Eq. - destruct (EQD _ Lt) as [_ [stk' [Eq' ?]]]. by simplify_eq/=. - - destruct kind; [by eexists..| |by eexists]. - destruct (retag_ref_is_freeze_is_Some α cids nxtp l otg T - (RawRef (bool_decide (mut = Mutable))) None) - as [bac Eq]; [by apply EQD|done..| |by eexists]. - simpl. clear -EQD. intros m stk Lt Eq. - destruct (EQD _ Lt) as [_ [stk' [Eq' ?]]]. simplify_eq/=. by destruct mut. - - destruct (retag_ref_is_freeze_is_Some α cids nxtp l otg T - (UniqueRef false) None) - as [bac Eq]; [by apply EQD|done..| |by eexists]. - simpl. clear -EQD. intros m stk Lt Eq. - destruct (EQD _ Lt) as [_ [stk' [Eq' ?]]]. by simplify_eq/=. -Qed. - - -Lemma retag_base_step' P σ l otg ntg pk T kind c' α' nxtp': - c' ∈ σ.(scs) → - retag σ.(sst) σ.(snp) σ.(scs) c' l otg kind pk T = - Some (ntg, α', nxtp') → - let σ' := mkState σ.(shp) α' σ.(scs) nxtp' σ.(snc) in - base_step P (Retag #[ScPtr l otg] #[ScCallId c'] pk T kind) σ #[ScPtr l ntg] σ' []. -Proof. - econstructor. { econstructor; eauto. } simpl. - econstructor; eauto. -Qed. - -Lemma retag_base_step P σ l c otg pk T kind - (BAR: c ∈ σ.(scs)) - (LOC: valid_block σ.(sst) σ.(scs) l otg pk T) - (WF: state_wf σ) : - ∃ ntg α' nxtp', - retag σ.(sst) σ.(snp) σ.(scs) c l otg kind pk T = - Some (ntg, α', nxtp') ∧ - let σ' := mkState σ.(shp) α' σ.(scs) nxtp' σ.(snc) in - base_step P (Retag #[ScPtr l otg] #[ScCallId c] pk T kind) σ #[ScPtr l ntg] σ' []. -Proof. - destruct σ as [h α cids nxtp nxtc]; simpl in *. - destruct (retag_is_freeze_is_Some α nxtp cids c l otg kind pk T) - as [[[h' α'] nxtp'] Eq]; [done|]. - exists h', α' , nxtp'. split; [done|]. - eapply retag_base_step'; eauto. -Qed. - *) - -(* Lemma syscall_base_step σ id : - base_step (SysCall id) σ [SysCallEvt id] #☠σ []. -Proof. - have EE: ∃ σ', base_step (SysCall id) σ [SysCallEvt id] #☠σ' [] ∧ σ' = σ. - { eexists. split. econstructor; econstructor. by destruct σ. } - destruct EE as [? [? ?]]. by subst. -Qed. *) diff --git a/theories/tree_borrows/steps_wf.v b/theories/tree_borrows/steps_wf.v index 2d4409a92391365c4019134ddd00e36fcd0053b7..4a2644ab6123e17c4b61538f4127e5af93f83e03 100755 --- a/theories/tree_borrows/steps_wf.v +++ b/theories/tree_borrows/steps_wf.v @@ -1,62 +1,22 @@ -(** This file has been adapted from the Stacked Borrows development, available at -https://gitlab.mpi-sws.org/FP/stacked-borrows -*) +(** The core idea of this file is to prove that all borrow steps preserve + well-formedness of trees. *) -From simuliris.tree_borrows Require Import helpers. -From simuliris.tree_borrows Require Export defs steps_foreach steps_access steps_preserve bor_lemmas. +From simuliris.tree_borrows Require Export defs tree_lemmas steps_foreach steps_preserve bor_lemmas. From iris.prelude Require Import options. (* weird GMAP stuff *) -Lemma gmap_dep_fold_ind_strong {B A P} (f : positive → A → B → B) (Q : B → gmap_dep A P → Prop) (b : B) j : - Q b GEmpty → - (∀ i p x mt r, gmap.gmap_dep_lookup i mt = None → - r = gmap.gmap_dep_fold f j b mt → - (∀ B' f' (b':B'), (f' (Pos.reverse_go i j) x (gmap.gmap_dep_fold f' j b' mt)) = gmap.gmap_dep_fold f' j b' (gmap.gmap_dep_partial_alter (λ _, Some x) i p mt)) → - Q r mt → - Q (f (Pos.reverse_go i j) x r) (gmap.gmap_dep_partial_alter (λ _, Some x) i p mt)) → - ∀ mt, Q (gmap.gmap_dep_fold f j b mt) mt. -Proof. - intros Hemp Hinsert mt. revert Q b j Hemp Hinsert. - induction mt as [|P ml mx mr ? IHl IHr] using gmap.gmap_dep_ind; - intros Q b j Hemp Hinsert; [done|]. - rewrite gmap.gmap_dep_fold_GNode; try done. - apply (IHr (λ y mt, Q y (gmap.GNode ml mx mt))). - { apply (IHl (λ y mt, Q y (gmap.GNode mt mx GEmpty))). - { destruct mx as [[p x]|]; [|done]. - replace (gmap.GNode gmap.GEmpty (Some (p,x)) gmap.GEmpty) with - (gmap.gmap_dep_partial_alter (λ _, Some x) 1 p gmap.GEmpty) by done. - by apply Hinsert. } - intros i p x mt r H1 H2 H3 H4. - replace (gmap.GNode (gmap.gmap_dep_partial_alter (λ _, Some x) i p mt) mx gmap.GEmpty) - with (gmap.gmap_dep_partial_alter (λ _, Some x) (i~0) p (gmap.GNode mt mx gmap.GEmpty)) - by (by destruct mt, mx as [[]|]). - apply Hinsert. 1,4: by rewrite ?gmap.gmap_dep_lookup_GNode. - 1: by destruct mt, mx as [[]|]; done. - intros B' f' b'. destruct mt, mx as [[]|]; simpl in *. - 1: done. 1: done. all: rewrite H3; by destruct gmap.gmap_dep_ne_partial_alter. } - intros i p x mt r H1 H2 H3 H4. - replace (gmap.GNode ml mx (gmap.gmap_dep_partial_alter (λ _, Some x) i p mt)) - with (gmap.gmap_dep_partial_alter (λ _, Some x) (i~1) p (gmap.GNode ml mx mt)) - by (by destruct ml, mx as [[]|], mt). - apply Hinsert. all: rewrite ?gmap.gmap_dep_lookup_GNode; try done. - 1: destruct ml, mx as [[]|], mt; simpl in *; done. - intros B' f' b'. destruct ml, mx as [[]|], mt; simpl in *. - 1,3,5,7: done. all: rewrite H3; by destruct gmap.gmap_dep_ne_partial_alter. -Qed. Lemma map_fold_ind_strong {K V B} `{Countable K} (P : B → gmap K V → Prop) (f : K → V → B → B) (b:B) (M : gmap K V) : P b ∅ → (∀ k v M, M !! k = None → (∀ B' f' (b':B'), map_fold f' b' (<[k:=v]> M) = f' k v (map_fold f' b' M)) → P (map_fold f b M) M → P (f k v (map_fold f b M)) (<[k:=v]> M)) → P (map_fold f b M) M. Proof. - intros H1 H2. destruct M as [M]. rewrite /map_fold /=. - apply (gmap_dep_fold_ind_strong _ (λ r M, P r (GMap M))); clear M; [done|]. - intros i [Hk] x mt r H0 -> H3; simpl. destruct (fmap_Some_1 _ _ _ Hk) as (k&Hk1&Hk2). subst i. - rewrite Hk1. - assert (GMapKey Hk = gmap_key_encode k) as Hk3 by (apply proof_irrel). rewrite Hk3. - apply (H2 _ _ (GMap mt)). 1: done. - intros ???. simpl. rewrite /map_fold /gmap_fold /= -Hk3 -H3 /= Hk1 //. + intros Hbase Hstep. eapply (map_first_key_ind (fun mm => P (map_fold f b mm) mm)). + - rewrite map_fold_empty. apply Hbase. + - intros k v m Hnone Hfirstkey HIH. + rewrite map_fold_insert_first_key //. eapply Hstep; [done| |done]. + intros B' f' b'. rewrite map_fold_insert_first_key //. Qed. @@ -888,7 +848,7 @@ Proof. destruct σ as [h trs cids nxtp nxtc]. destruct σ' as [h' trs' cids' nxtp' nxtc']. simpl. intros BS IS WF. inversion BS. clear BS. simplify_eq. - inversion IS as [x| | | | | | | | | |]; clear IS. simpl in *; simplify_eq. constructor; simpl. + inversion IS as [x| | | | | | | | |]; clear IS. simpl in *; simplify_eq. constructor; simpl. - apply same_blocks_init_extend; [lia|]. apply WF. - apply extend_trees_wf. @@ -1758,7 +1718,7 @@ Proof. destruct σ' as [h' trs' cids' nxtp' nxtc']. simpl. intros BS IS WF. inversion BS; clear BS; simplify_eq. - inversion IS as [ | | | | | | | |trs'' ???? ACC | | ]; clear IS; simplify_eq. + inversion IS as [ | | | | | | |trs'' ???? ACC | | ]; clear IS; simplify_eq. destruct (trees_deallocate_isSome _ _ _ _ _ _ (mk_is_Some _ _ ACC)) as [x [Lookup Update]]. assert (each_tree_parents_more_init trs'') as HH1. { eapply apply_within_trees_deallocate_compat_parents_more_init; try done. @@ -1845,26 +1805,11 @@ Proof. destruct σ' as [h' trs' cids' nxtp' nxtc']. simpl. intros BS IS WF. inversion BS; clear BS; simplify_eq. - inversion IS as [ |?????? ACC| | | | | | | | | ]; clear IS; simplify_eq. + inversion IS as [ |?????? ACC| | | | | | | | ]; clear IS; simplify_eq. - eapply (access_step_wf_inner σ false); done. - by destruct σ. Qed. -Lemma failed_copy_step_wf σ σ' e e' l bor T efs : - mem_expr_step σ.(shp) e (FailedCopyEvt l bor T) σ'.(shp) e' efs → - bor_step σ.(strs) σ.(scs) σ.(snp) σ.(snc) - (FailedCopyEvt l bor T) - σ'.(strs) σ'.(scs) σ'.(snp) σ'.(snc) → - state_wf σ → state_wf σ'. -Proof. - destruct σ as [h α cids nxtp nxtc]. - destruct σ' as [h' α' cids' nxtp' nxtc']. simpl. - intros BS IS WF. - inversion BS. clear BS. simplify_eq. - inversion IS; clear IS; simplify_eq. - done. -Qed. - (* TODO less equalities makes applying the rule easier, see _sane version below *) Lemma write_mem_dom l (vl : value) h h' (DEFINED: ∀ i : nat, (i < length vl)%nat → (l +â‚— i) ∈ dom h) @@ -2004,7 +1949,7 @@ Proof. destruct σ' as [h' trs' cids' nxtp' nxtc']. simpl. intros BS IS WF. inversion BS; clear BS; simplify_eq. - inversion IS as [ | | | |?????? ACC |???? RANGE_SIZE| | | | | ]; clear IS; simplify_eq. + inversion IS as [ | | |?????? ACC |???? RANGE_SIZE| | | | | ]; clear IS; simplify_eq. 2: { simpl in RANGE_SIZE. destruct vl; last done. simpl. done. } constructor; simpl. - rewrite /same_blocks. @@ -3217,7 +3162,7 @@ Proof. destruct σ' as [h' trs' cids' nxtp' nxtc']. simpl. intros BS IS WF. inversion BS. clear BS. simplify_eq. - inversion IS as [| | | | | |trsmid ???????? EXISTS_TAG FRESH_CHILD RETAG_EFFECT READ_ON_REBOR| | | |]. + inversion IS as [| | | | |trsmid ???????? EXISTS_TAG FRESH_CHILD RETAG_EFFECT READ_ON_REBOR| | | |]. 2: by simplify_eq. simplify_eq. eapply retag_step_wf_inner in WF as (WF&TAG_AFTER_ADD); simpl in WF|-*. 2-5: try done. eapply access_step_wf_inner in WF. all: done. @@ -3231,7 +3176,7 @@ Proof. - eapply alloc_step_wf; eauto. - eapply dealloc_step_wf; eauto. - eapply read_step_wf; eauto. - - eapply failed_copy_step_wf; eauto. + (* - eapply failed_copy_step_wf; eauto. *) - eapply write_step_wf; eauto. - eapply initcall_step_wf; eauto. - eapply endcall_step_wf; eauto. diff --git a/theories/tree_borrows/tkmap_view.v b/theories/tree_borrows/tkmap_view.v index 1e2e3bf2fc7874a19492ab906eda7a0179119d99..51c4c5fcfbc198490db1be440dd50398e5b3f091 100755 --- a/theories/tree_borrows/tkmap_view.v +++ b/theories/tree_borrows/tkmap_view.v @@ -1,7 +1,3 @@ -(** This file has been adapted from the Iris development, available at - https://gitlab.mpi-sws.org/iris/iris -*) - From Coq.QArith Require Import Qcanon. From iris.algebra Require Export view gmap frac dfrac. From iris.algebra Require Import local_updates proofmode_classes big_op. @@ -13,16 +9,14 @@ From simuliris.tree_borrows Require Export defs. (gmap_view has since been updated so we could now use it directly, but this code predates the generalized gmap_view for arbitrary CRMA.) *) (* Currently, we place a strong restriction on the shape of a location's stack: - A tag can be of one of two kinds: + A tag can be of one of several kinds: - tk_pub: the tag is public (can be shared, assertion is persistent) - - tk_unq: the tag is unique (cannot be shared, assertion is not persistent). - - tk_loc: the tag is local + - tk_unq: the tag is unique (cannot be shared, assertion is not persistent). This is further parameterized by whether it is reserved or activated. + - tk_loc: the tag is local (a local variable whose address has not been taken) *) -(* TODO: allow a local update from tk_unq to tk_pub *) Definition tagKindR := csumR (exclR unitO) (csumR (csumR (exclR unitO) (exclR unitO)) unitR). - Canonical Structure tag_kindO := leibnizO tag_kind. Global Instance tagKindR_discrete : CmraDiscrete tagKindR. diff --git a/theories/tree_borrows/tree.v b/theories/tree_borrows/tree.v index 72039ac16fea00c9b9f15b2538fdb838f62a1305..400ee57e927b73d56d066ffbfdef4cfc18143be0 100644 --- a/theories/tree_borrows/tree.v +++ b/theories/tree_borrows/tree.v @@ -19,30 +19,36 @@ Proof. Qed. -(* Generic tree - Note: we are using the "tilted" representation of n-ary trees - where the binary children are the next n-ary sibling and - the first n-ary child. - This is motivated by the much nicer induction principles - we get, but requires more careful definition of the - parent-child relationship. +(* Generic tree *) +(* NOTE: we are using the "tilted" representation of n-ary trees + where the binary children are the next n-ary sibling and the first n-ary child. + This is motivated by the much nicer induction principles we get, + but requires more careful definition of the parent-child relationship. + In any case anything we do here is abstracted away as far as the more + high-level principles are concerned. *) Inductive tree X := | empty | branch (data:X) (sibling child:tree X) . -(* x +(* EXAMPLE: + + the n-ary tree of width 4 and height 2 + + x |- y1 |- y2 |- y3 |- y4 + is encoded by a binary tree of height 5 + branch x empty (branch y1 (branch y2 (branch y3 - (branch y4) + (branch y4 empty empty) empty empty empty @@ -56,6 +62,11 @@ Definition of_branch {X} (br:tbranch X) : tree X := let '(root, lt, rt) := br in branch root lt rt. +Definition root {X} (br:tbranch X) + : X := let '(r, _, _) := br in r. + +(** The main traversal operation is the folding. *) + Definition fold_subtrees {X Y} (unit:Y) (combine:tbranch X -> Y -> Y -> Y) : tree X -> Y := fix aux tr : Y := match tr with @@ -63,13 +74,13 @@ Definition fold_subtrees {X Y} (unit:Y) (combine:tbranch X -> Y -> Y -> Y) | branch data sibling child => combine (data, sibling, child) (aux sibling) (aux child) end. -Definition root {X} (br:tbranch X) - : X := let '(r, _, _) := br in r. - Definition fold_nodes {X Y} (unit:Y) (combine:X -> Y -> Y -> Y) : tree X -> Y := fold_subtrees unit (fun subtree sibling child => combine (root subtree) sibling child). -Definition map_nodes {X Y} (fn:X -> Y) : tree X -> tree Y := fold_nodes empty (compose branch fn). +(** From which we define [map] as is standard. *) + +Definition map_nodes {X Y} (fn:X -> Y) : tree X -> tree Y := + fold_nodes empty (compose branch fn). Definition join_nodes {X} : tree (option X) -> option (tree X) := fix aux tr {struct tr} : option (tree X) := @@ -82,6 +93,9 @@ Definition join_nodes {X} Some $ branch data sibling child end. +(** Quantifiers over trees, universal and existential. + All of them are of course decidable. *) + Definition every_subtree {X} (prop:tbranch X -> Prop) (tr:tree X) := fold_subtrees True (fun sub lt rt => prop sub /\ lt /\ rt) tr. Global Instance every_subtree_dec {X} prop (tr:tree X) : (forall x, Decision (prop x)) -> Decision (every_subtree prop tr). @@ -100,9 +114,14 @@ Definition exists_node {X} (prop:X -> Prop) (tr:tree X) := fold_nodes False (fun Global Instance exists_node_dec {X} prop (tr:tree X) : (forall x, Decision (prop x)) -> Decision (exists_node prop tr). Proof. intro. induction tr; solve_decision. Defined. + +(** Alternative to a quantifier, we can state exactly how many nodes + satisfy a certain property. From this we derive unique existential quantification. *) Definition count_nodes {X} (prop:X -> bool) := fold_nodes 0 (fun data lt rt => (if prop data then 1 else 0) + lt + rt). +(* As a consequence of the representation, strict children are all + the nodes from the right subtree. *) Definition exists_strict_child {X} (prop:X -> Prop) : tbranch X -> Prop := fun '(_, _, child) => exists_node prop child. Global Instance exists_strict_child_dec {X} prop (tr:tbranch X) : @@ -114,6 +133,11 @@ Definition empty_children {X} (tr:tbranch X) let '(_, _, children) := tr in children = empty. +(** Other main tree operation is insertion. + We use a somewhat nonstandard definition in which insertion occurs + as a child of every node that satisfies a certain property. + You will need quantifiers about the existence of nodes that satisfy + [search_dec] if you want to make sure that the node is actually inserted. *) Definition insert_child_at {X} (tr:tree X) (ins:X) (search:X -> Prop) {search_dec:forall x, Decision (search x)} : tree X := (fix aux tr : tree X := match tr with @@ -128,7 +152,10 @@ Definition insert_child_at {X} (tr:tree X) (ins:X) (search:X -> Prop) {search_de ) tr. Definition fold_siblings {X Y} (empty:Y) (fn : X -> Y -> Y) (tr : tree X) : Y := - fold_nodes empty (λ x tl _, fn x tl) tr. + fold_nodes empty (λ this siblings _, fn this siblings) tr. + +(** Immediate children are a bit more tricky to reason about. + They are the entire leftmost *branch* of the right subtree. *) Fixpoint fold_immediate_children_at {X Y} (prop:X -> bool) (empty:Y) (fn : X -> Y -> Y) (tr : tree X) : list Y := match tr with empty => nil | branch x tl tr => (if prop x then [fold_siblings empty fn tr] else nil) ++ diff --git a/theories/tree_borrows/tree_access_laws.v b/theories/tree_borrows/tree_access_laws.v index 3f01f843e3dd78c40271b7d439c7c889c8d97ecb..b99f619f911499eb7ad08bf1e36d80c940af8e78 100644 --- a/theories/tree_borrows/tree_access_laws.v +++ b/theories/tree_borrows/tree_access_laws.v @@ -25,7 +25,7 @@ Proof. destruct (trs !! blk); [|tauto]. intros Ex Eq. injection Eq; intros; subst. assumption. Qed. -(***** not part of the API *****) +(***** END not part of the API *****) Lemma trees_contain_trees_lookup_1 trs blk tg : wf_trees trs → @@ -329,8 +329,8 @@ Proof. Qed. (* Reverse lifting to single trees. - This is a roundabout of proving these, but we started with the lemmas above and this way there is the least refactoring effort. *) - + This is a roundabout of proving these, but we started with the lemmas above + and this way there is the least refactoring effort. *) Lemma wf_tree_wf_singleton_any z tr : wf_tree tr → wf_trees (singletonM z tr). Proof. @@ -427,7 +427,8 @@ Proof. Qed. -(* Some more facts about trees. These could be refactored, maybe? *) +(* Some more facts about trees. *) +(* TODO: These could be refactored, maybe? *) Lemma apply_access_perm_access_remains_disabled b acc rel isprot itmo itmn : maybe_non_children_only b (apply_access_perm acc) rel isprot itmo = Some itmn → @@ -768,4 +769,4 @@ Proof. 2: done. 2: by eapply Hwf. 2: done. 2: done. - rewrite /= insert_id //. - by exists it. -Qed. \ No newline at end of file +Qed. diff --git a/theories/tree_borrows/tree_lemmas.v b/theories/tree_borrows/tree_lemmas.v index b0470ca7cc6f46af96a3b25c25fa87215563e2ad..2eb5bf0dba6bb863eb05af30d48ef3974bae97b1 100644 --- a/theories/tree_borrows/tree_lemmas.v +++ b/theories/tree_borrows/tree_lemmas.v @@ -1,7 +1,7 @@ From Equations Require Import Equations. From iris.prelude Require Import prelude options. From stdpp Require Export gmap. -From simuliris.tree_borrows Require Export lang_base notation tree. +From simuliris.tree_borrows Require Export tree. From iris.prelude Require Import options. Implicit Type (V W X Y:Type). @@ -246,42 +246,6 @@ Proof. all: simpl; auto. Qed. -(* -Lemma exists_child_transitive {X} (search search':Tprop X) : - forall tr, - exists_node search tr -> - tree_AtNode search (tree_ChildExists search') tr -> - exists_node search' tr. -Proof. - intros tr Exists Search. - induction tr; simpl; auto. - destruct Search as [Search0 [Search1 Search2]]. - destruct Exists as [Exists0 | [Exists1 | Exists2]]; auto. - destruct (Search0 Exists0); auto. -Qed. - -Lemma AtNodeExists_transitive {X} (search search' search'':Tprop X) : - forall tr, - tree_AtNode search (tree_ChildExists search') tr -> - tree_AtNode search' (tree_ChildExists search'') tr -> - tree_AtNode search (tree_ChildExists search'') tr. -Proof. - intros tr Search Search'. - induction tr; auto. - destruct Search' as [Search' [Search'1 Search'2]]. - destruct Search as [Search [Search1 Search2]]. - pose Found1 := (IHtr1 Search1 Search'1). - pose Found2 := (IHtr2 Search2 Search'2). - simpl; try repeat split; auto. - clear Found1; clear Found2; clear IHtr1; clear IHtr2. - intro Found; destruct (Search Found) as [Found' | FoundSub]. - - destruct (Search' Found') as [Found'' | Found'Sub]; auto. - - right; clear Found; clear Search; clear Search1; clear Search2. - clear Search'. - apply (ExistsAtNode_transitive search'); auto. -Qed. -*) - Lemma insert_true_preserves_every {X} (tr:tree X) (ins:X) (search prop:X -> Prop) {search_dec:forall x, Decision (search x)} : prop ins -> @@ -370,21 +334,6 @@ Proof. * right; right; auto. Qed. -(* -Lemma insert_preserves_ChildExists {X} (ins:X) (tr:tree X) (search prop:Tprop X) - {search_dec:forall x, Decision (search x)} : - tree_ChildExists prop tr -> tree_ChildExists prop (insert_child_at tr ins search). -Proof. - intro Exists. - destruct tr; simpl; auto. - destruct (decide (search data)) eqn:Found; simpl; auto. - all: simpl in Exists. - all: inversion Exists as [Ex0 | Ex2]; auto. - 1: right; right; left; apply insert_preserves_Exists; auto. - right; apply insert_preserves_Exists; auto. -Qed. -*) - Lemma exists_insert_requires_parent {X} (ins:X) (search prop:X -> Prop) {search_dec:forall x, Decision (search x)} : forall tr, @@ -414,7 +363,7 @@ Proof. right; right. destruct Hyp2 as [Contra | [Hyp2Sub | Hyp2Empty]]; auto; contradiction. Qed. -Lemma exists_subtree_transitive br prop (tr:tree item) : +Lemma exists_subtree_transitive T br prop (tr:tree T) : exists_subtree (eq br) tr -> exists_subtree prop (of_branch br) -> exists_subtree prop tr. @@ -428,7 +377,7 @@ Proof. - right; right. apply IHtr2; auto. Qed. -Lemma every_subtree_transitive br prop (tr:tree item) : +Lemma every_subtree_transitive T br prop (tr:tree T) : every_subtree (eq br) tr -> every_subtree prop (of_branch br) -> every_subtree prop tr. @@ -442,7 +391,7 @@ Proof. try repeat split; auto. Qed. -Lemma exists_node_transitive br prop (tr:tree item) : +Lemma exists_node_transitive T br prop (tr:tree T) : exists_subtree (eq br) tr -> exists_node prop (of_branch br) -> exists_node prop tr. diff --git a/theories/tree_borrows/trees_equal/disabled_in_practice.v b/theories/tree_borrows/trees_equal/disabled_in_practice.v index 6bdb6d5be7b7c86b38b420d876dc78bc07ac225b..9e635cd1f8421b380ce331273814b6a179e8e6d6 100644 --- a/theories/tree_borrows/trees_equal/disabled_in_practice.v +++ b/theories/tree_borrows/trees_equal/disabled_in_practice.v @@ -1,4 +1,3 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) From iris.proofmode Require Export proofmode. From iris.bi.lib Require Import fractional. From iris.base_logic.lib Require Import ghost_map. diff --git a/theories/tree_borrows/trees_equal/random_lemmas.v b/theories/tree_borrows/trees_equal/random_lemmas.v index 6a745b9d77d59f30e91d744b643d021e789a51c3..7abccdfb6156b37c222dffa7f93d225eb1ef9d17 100644 --- a/theories/tree_borrows/trees_equal/random_lemmas.v +++ b/theories/tree_borrows/trees_equal/random_lemmas.v @@ -1,4 +1,3 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) From iris.proofmode Require Export proofmode. From iris.bi.lib Require Import fractional. From iris.base_logic.lib Require Import ghost_map. @@ -13,7 +12,6 @@ From simuliris.tree_borrows.trees_equal Require Import trees_equal_base. From iris.prelude Require Import options. -(* TODO cleanup *) Section utils. Lemma every_node_iff_every_lookup @@ -270,7 +268,7 @@ Section utils. Qed. - (* FIXME: move this elsewhere *) + (* FIXME: This is a very low level lemma, move this elsewhere ? *) Lemma if_fun_absorb_args {X Y} {b : bool} {x : X} {f g : X -> Y} : (if b then f else g) x = if b then f x else g x. Proof. destruct b; reflexivity. Qed. @@ -443,4 +441,4 @@ Section utils. Qed. -End utils. \ No newline at end of file +End utils. diff --git a/theories/tree_borrows/trees_equal/trees_equal.v b/theories/tree_borrows/trees_equal/trees_equal.v deleted file mode 100644 index c80419ce21dadf9cce1c612d7f9880feb2244b0c..0000000000000000000000000000000000000000 --- a/theories/tree_borrows/trees_equal/trees_equal.v +++ /dev/null @@ -1,4167 +0,0 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) -From iris.proofmode Require Export proofmode. -From iris.bi.lib Require Import fractional. -From iris.base_logic.lib Require Import ghost_map. -From simuliris.base_logic Require Export gen_sim_prog. -From simuliris.simulation Require Export slsls gen_log_rel. -From simuliris.simulation Require Import lifting. -From simuliris.tree_borrows Require Import tkmap_view. -From simuliris.tree_borrows Require Export defs. -From simuliris.tree_borrows Require Export steps_wf. -From simuliris.tree_borrows Require Import steps_progress. -From iris.prelude Require Import options. - - -(* TODO cleanup *) -Section utils. - - Definition tag_valid (upper : tag) (n : tag) : Prop := (n < upper)%nat. - - Lemma tag_valid_mono upper1 upper2 n1 n2 : - tag_valid upper1 n1 → - (upper1 ≤ upper2)%nat → - (n2 ≤ n1)%nat → - tag_valid upper2 n2. - Proof. - rewrite /tag_valid. lia. - Qed. - - Context (C : gset call_id). - - (* trees_equal is almost symmetric. To still get nice reasoning rules around symmetry and stuff, - we add a directionality flags for all rules that hold on both sides, so that we can reason by - symmetry -> foo -> symmetry and so only have to formulate foo to operate on one side *) - Inductive direction := Forwards | Backwards. - - Inductive pseudo_conflicted (tr : tree item) (tg : tag) (l : Z) - : res_conflicted → Prop := - | pseudo_conflicted_conflicted : - (* a Conflicted marker makes the permission literally conflicted *) - pseudo_conflicted tr tg l ResConflicted - | pseudo_conflicted_cousin_init tg_cous it_cous : - (* If it's not actually conflicted, it can be pseudo conflicted if there is *) - (* A cousin that is protected *) - rel_dec tr tg tg_cous = Foreign Cousin -> - tree_lookup tr tg_cous it_cous -> - protector_is_active it_cous.(iprot) C -> - (* and who on this location is initalized not disabled *) - (item_lookup it_cous l).(perm) ≠Disabled -> - (item_lookup it_cous l).(initialized) = PermInit -> - pseudo_conflicted tr tg l ResActivable - . - - Inductive pseudo_disabled (tr : tree item) (tg : tag) (l : Z) : permission → (option protector) → Prop := - | pseudo_disabled_disabled prot : - (* a Disabled it also pseudo-disabled *) - pseudo_disabled _ _ _ Disabled prot - | pseudo_disabled_cousin_active tg_cous it_cous lp prot : - rel_dec tr tg tg_cous = Foreign Cousin -> - tree_lookup tr tg_cous it_cous -> - protector_is_active it_cous.(iprot) C -> - (item_lookup it_cous l) = mkPerm PermInit Active -> - (* This is not allowed, since it actually survives foreign writes. *) - lp ≠ReservedIM -> - pseudo_disabled _ _ _ lp prot - . - - (* this implicitly requires (by state_wf) that it's not (protected and initialized) *) - (* it also implies (via state_wf) that all children are not (protected and initialized) *) - Inductive is_disabled (tr : tree item) (tg : tag) (l : Z) : lazy_permission → option protector → Prop := - | disabled_init prot : - is_disabled _ _ _ (mkPerm PermInit Disabled) prot - | disabled_pseudo lp prot : - pseudo_disabled tr tg l lp prot → - is_disabled _ _ _ (mkPerm PermLazy lp) prot. - - Inductive disabled_in_practice (tr : tree item) (tg : tag) (witness : tag) (l : Z) - : Prop := - | disabled_parent it_witness inclusive : - (* Doesn't have to be immediate, just any parent is Disabled *) - rel_dec tr tg witness = Child inclusive -> - tree_lookup tr witness it_witness -> - is_disabled tr witness l (item_lookup it_witness l) (iprot it_witness) -> - disabled_in_practice tr tg witness l - . - - Inductive parent_has_perm p (tr : tree item) (tg : tag) (witness : tag) (l : Z) - : Prop := - (* This means being Reserved and having a parent that is exactly Frozen. - [frozen_in_practice] behaves indistinguishably from Frozen. - We could probably make [Frozen] and [frozen_in_practice] equivalent, but - this shouldn't turn up in practice. *) - | mk_parent_has_perm it_witness inclusive : - rel_dec tr tg witness = Child inclusive -> - tree_lookup tr witness it_witness -> - (item_lookup it_witness l).(perm) = p -> - (* be initialized so that protectors trigger if applicable *) - (item_lookup it_witness l).(initialized) = PermInit -> - parent_has_perm p tr tg witness l - . - - Definition frozen_in_practice := parent_has_perm Frozen. - - Inductive one_sided_sim : Prop -> permission -> permission -> Prop := - | one_sided_sim_active isprot : - ¬ isprot -> - one_sided_sim isprot Frozen Active - | one_sided_sim_res_confl isprot : - isprot -> - one_sided_sim isprot (Reserved ResConflicted) (Reserved ResActivable). - - Definition directional_simulation d isprot p1 p2 : Prop := - match d with - | Forwards => one_sided_sim isprot p1 p2 - | Backwards => one_sided_sim isprot p2 p1 - end. - - Inductive perm_eq_up_to_C (tr1 tr2 : tree item) (tg : tag) (l : Z) cid d - : lazy_permission -> lazy_permission -> Prop := - | perm_eq_up_to_C_refl p : - (* Usually the permissions will be equal *) - perm_eq_up_to_C tr1 tr2 tg l cid d p p - | perm_eq_up_to_C_pseudo ini confl1 confl2 : - (* But if they are protected *) - protector_is_active cid C -> - (* And both pseudo-conflicted *) - pseudo_conflicted tr1 tg l confl1 -> - pseudo_conflicted tr2 tg l confl2 -> - (* then we can allow a small difference *) - perm_eq_up_to_C tr1 tr2 tg l cid d - {| initialized := ini; perm := Reserved confl1 |} - {| initialized := ini; perm := Reserved confl2 |} - | perm_eq_up_to_C_pseudo_post_prot ini confl1 confl2 : - (* But if they are not protected *) - ¬ protector_is_active cid C -> - (* then we can allow a small difference *) - perm_eq_up_to_C tr1 tr2 tg l cid d - {| initialized := ini; perm := Reserved confl1 |} - {| initialized := ini; perm := Reserved confl2 |} - | perm_eq_up_to_C_pseudo_disabled p1 p2 : - (* A pseudo-disabled tag is one that's lazy, does not support child accesses due to a protected Active cousin, - and will become Disabled on protector-end write for that cousin. - It must be lazy, because a protected active has no non-disabled initialized cousins. - Only exception: ¬prot Reserved InteriorMut, for which this case here does not apply. *) - pseudo_disabled tr1 tg l p1 cid -> - pseudo_disabled tr2 tg l p2 cid -> - perm_eq_up_to_C tr1 tr2 tg l cid d - {| initialized := PermLazy; perm := p1 |} - {| initialized := PermLazy; perm := p2 |} - | perm_eq_up_to_C_disabled_parent witness_tg p p' : - (* Finally if they have a Disabled parent we allow anything (unprotected) since - nothing is possible through this tag anyway *) - disabled_in_practice tr1 tg witness_tg l -> - disabled_in_practice tr2 tg witness_tg l -> - (* Added initialization requirement to help with the lemma [perm_eq_up_to_C_same_init] *) - (initialized p = initialized p') -> - perm_eq_up_to_C tr1 tr2 tg l cid d p p' - | perm_eq_up_to_C_frozen_parent ini confl1 confl2 witness_tg : - (* not needed for IM, that's already covered by refl *) - (* only the source side must be Frozen. This already implies the other side is frozen in practice, - or the same with Active, or we're disabled on both. *) - frozen_in_practice (match d with Forwards => tr1 | _ => tr2 end) tg witness_tg l -> - perm_eq_up_to_C tr1 tr2 tg l cid d - {| initialized := ini; perm := Reserved confl1 |} - {| initialized := ini; perm := Reserved confl2 |} - | perm_eq_up_to_C_directional p1 p2 ini : - directional_simulation d (protector_is_active cid C) p1 p2 -> - perm_eq_up_to_C tr1 tr2 tg l cid d - {| initialized := ini; perm := p1 |} - {| initialized := ini; perm := p2 |} - . - - Definition loc_eq_up_to_C (tr1 tr2 : tree item) (tg : tag) d (it1 it2 : item) (l : Z) := - it1.(iprot) = it2.(iprot) - /\ perm_eq_up_to_C tr1 tr2 tg l it1.(iprot) d (item_lookup it1 l) (item_lookup it2 l). - - Definition item_eq_up_to_C (tr1 tr2 : tree item) (tg : tag) d (it1 it2 : item) := - forall l, loc_eq_up_to_C tr1 tr2 tg d it1 it2 l. - - Definition tree_equal d (tr1 tr2 : tree item) := - (* To be equal trees must have exactly the same tags *) - (forall tg, tree_contains tg tr1 <-> tree_contains tg tr2) - (* and define all the same relationships between those tags *) - /\ (forall tg tg', rel_dec tr1 tg tg' = rel_dec tr2 tg tg') - (* and have their permissions be equal up to C on all locations *) - (* FIXME: maybe think about reformulating ∧ (∀ t it1 it2, tree_lookup t it1 tr1 -> tree_lookup t it2 tr2 -> it_rel it1 it2) *) - /\ (forall tg, tree_contains tg tr1 -> - exists it1 it2, - tree_lookup tr1 tg it1 - /\ tree_lookup tr2 tg it2 - /\ item_eq_up_to_C tr1 tr2 tg d it1 it2 - ). - - Definition trees_equal d (t1 t2 : trees) := - ∀ blk, option_Forall2 (tree_equal d) (t1 !! blk) (t2 !! blk). - - - Lemma loc_eq_up_to_C_reflexive - {d tr1 tr2 tg it l} - : loc_eq_up_to_C tr1 tr2 tg d it it l. - Proof. - split. - + reflexivity. - + apply perm_eq_up_to_C_refl. - Qed. - - Lemma item_eq_up_to_C_reflexive - {d tr1 tr2 tg it} - : item_eq_up_to_C tr1 tr2 tg d it it. - Proof. - intro l. - apply loc_eq_up_to_C_reflexive. - Qed. - - Lemma tree_equal_reflexive d tr - (AllUnique : forall tg, tree_contains tg tr -> exists it, tree_item_determined tg it tr) - : tree_equal d tr tr. - Proof. - try repeat split. - - tauto. - - tauto. - - intros tg Ex. - destruct (AllUnique tg Ex). - eexists. eexists. - try repeat split. - + assumption. - + eassumption. - + assumption. - + eassumption. - + apply item_eq_up_to_C_reflexive. - Qed. - - - Lemma trees_equal_reflexive d trs - (AllUnique : forall blk tr tg, - trs !! blk = Some tr -> - tree_contains tg tr -> - exists it, tree_item_determined tg it tr) - : trees_equal d trs trs. - Proof. - intros blk. - specialize (AllUnique blk). - remember (trs !! blk) as at_blk. - destruct at_blk. - - apply Some_Forall2. - apply tree_equal_reflexive. - intro tg. - eapply AllUnique. - reflexivity. - - apply None_Forall2. - Qed. - - - Lemma trees_equal_same_tags d (trs1 trs2 : trees) (tg : tag) (blk : block) : - trees_equal d trs1 trs2 -> - trees_contain tg trs1 blk <-> trees_contain tg trs2 blk. - Proof. - intro Equals. - rewrite /trees_equal in Equals. - specialize (Equals blk). - rewrite /trees_contain /trees_at_block. - destruct (trs1 !! blk) as [tr1|]; - destruct (trs2 !! blk) as [tr2|]; - inversion Equals as [?? Equal|]. - 2: tauto. - subst. - destruct Equal as [SameTags _]. - apply SameTags. - Qed. - - Lemma trees_equal_empty d : trees_equal d ∅ ∅. - Proof. - apply trees_equal_reflexive. - intros blk tr tg LookupEmp. - inversion LookupEmp. - Qed. - - Definition direction_flip d := match d with - Forwards => Backwards - | Backwards => Forwards end. - - Lemma direction_flip_inv d : direction_flip (direction_flip d) = d. - Proof. by destruct d. Qed. - - Lemma perm_eq_up_to_C_sym - {d tr1 tr2 tg l cid perm1 perm2} - : perm_eq_up_to_C tr1 tr2 tg l cid d perm1 perm2 - -> perm_eq_up_to_C tr2 tr1 tg l cid (direction_flip d) perm2 perm1. - Proof. - intro EqC. - inversion EqC. - + econstructor 1. - + econstructor 2; eassumption. - + econstructor 3; eassumption. - + econstructor 4; eassumption. - + econstructor 5; try eassumption. - done. - + econstructor 6; destruct d; eassumption. - + econstructor 7; destruct d; eassumption. - Qed. - - Lemma loc_eq_up_to_C_sym - {d tr1 tr2 tg it1 it2 l} - : loc_eq_up_to_C tr1 tr2 tg d it1 it2 l - -> loc_eq_up_to_C tr2 tr1 tg (direction_flip d) it2 it1 l. - Proof. - intros [SameProt EqC]. - split. - + auto. - + apply perm_eq_up_to_C_sym. - rewrite <- SameProt. - assumption. - Qed. - - Lemma item_eq_up_to_C_sym - {d tr1 tr2 tg it1 it2} - : item_eq_up_to_C tr1 tr2 tg d it1 it2 - -> item_eq_up_to_C tr2 tr1 tg (direction_flip d) it2 it1. - Proof. - intros EqC l. - apply loc_eq_up_to_C_sym. - auto. - Qed. - - Lemma tree_equal_sym {d} tr1 tr2 : tree_equal d tr1 tr2 → tree_equal (direction_flip d) tr2 tr1. - Proof. - rewrite /tree_equal. - intros [SameTg [SameRel EqC]]. - split; [|split]. - + intro tg. rewrite SameTg. tauto. - + intros tg tg'. rewrite SameRel. tauto. - + intros tg Ex. - rewrite <- SameTg in Ex. - destruct (EqC tg Ex) as [it1 [it2 [Lookup1 [Lookup2 EqCsub]]]]. - exists it2, it1. - split; [|split]. - * assumption. - * assumption. - * apply item_eq_up_to_C_sym. - assumption. - Qed. - - Lemma trees_equal_sym {d} trs1 trs2 : trees_equal d trs1 trs2 → trees_equal (direction_flip d) trs2 trs1. - Proof. - rewrite /trees_equal. - intros Equals blk. - specialize (Equals blk). - inversion Equals; simplify_eq; econstructor. - by eapply tree_equal_sym. - Qed. - - Lemma every_node_iff_every_lookup - {tr prop} - (GloballyUnique : forall tg, tree_contains tg tr -> exists it, tree_item_determined tg it tr) - : every_node prop tr <-> forall tg it, tree_lookup tr tg it -> prop it. - Proof. - rewrite every_node_eqv_universal. - split. - - intros Every tg it [Ex Unq]. - apply Every. - eapply exists_node_increasing; [eassumption|]. - eapply every_node_increasing; [eassumption|]. - erewrite every_node_eqv_universal. - intros. symmetry. auto. - - intros Lookup it Exists. - apply (Lookup (itag it)). - assert (tree_contains it.(itag) tr) as Ex. { - eapply exists_node_increasing; [eassumption|]. - erewrite every_node_eqv_universal. - intros. subst. auto. - } - destruct (GloballyUnique _ Ex) as [it' Unq']. - assert (it = it') as Eq. { - apply (proj1 (every_node_eqv_universal _ _) Unq' it Exists). - auto. - } - rewrite -Eq in Unq'. - split; assumption. - Qed. - - Lemma tree_equal_implies_globally_unique_1 - {d tr1 tr2} : - tree_equal d tr1 tr2 -> - forall tg, tree_contains tg tr1 -> exists it, tree_item_determined tg it tr1. - Proof. - intros [ExIff [SameRel Lookup]] tg Ex. - destruct (Lookup _ Ex) as [it1 [it2 [Lookup1 [Lookup2 EqC]]]]. - exists it1. - apply Lookup1. - Qed. - - Lemma tree_equal_implies_globally_unique_2 - {d tr1 tr2} : - tree_equal d tr1 tr2 -> - forall tg, tree_contains tg tr2 -> exists it, tree_item_determined tg it tr2. - Proof. - intro Eq. - pose proof (tree_equal_sym _ _ Eq) as Eq'. - revert Eq'. - apply tree_equal_implies_globally_unique_1. - Qed. - - - Lemma tree_equal_transfer_lookup_1 - {d tr1 tr2 tg it1} : - tree_equal d tr1 tr2 -> - tree_lookup tr1 tg it1 -> - exists it2, - tree_lookup tr2 tg it2 - /\ item_eq_up_to_C tr1 tr2 tg d it1 it2. - Proof. - intros [SameTg [SameRel MkLookup]] [Ex1 Unq1]. - destruct (MkLookup _ Ex1) as [it1' [it2 [Lookup1' [Lookup2 EqC']]]]. - assert (it1 = it1') by (eapply tree_determined_unify; [eassumption|apply Unq1|apply Lookup1']). - subst it1'. - exists it2. - split; assumption. - Qed. - - Lemma tree_equal_transfer_lookup_2 - {d tr1 tr2 tg it2} : - tree_equal d tr1 tr2 -> - tree_lookup tr2 tg it2 -> - exists it1, - tree_lookup tr1 tg it1 - /\ item_eq_up_to_C tr1 tr2 tg d it1 it2. - Proof. - intros Eq Lookup2. - pose proof (tree_equal_sym _ _ Eq) as Eq'. - destruct (tree_equal_transfer_lookup_1 Eq' Lookup2) as [it1 [Lookup1 EqC']]. - exists it1; split; [assumption|]. - rewrite -(direction_flip_inv d). - apply item_eq_up_to_C_sym. - assumption. - Qed. - - Lemma is_Some_ignore_bind - {X Y} {o : option X} {g : X -> Y} : - is_Some (o ≫= fun x => Some (g x)) <-> is_Some o. - Proof. - destruct o; simpl; split; intro H. - - auto. - - auto. - - inversion H; discriminate. - - inversion H; discriminate. - Qed. - - Lemma mutual_parent_child_both_or_neither - {tg tg' tr} : - StrictParentChildIn tg tg' tr -> - StrictParentChildIn tg' tg tr -> - forall br, - exists_subtree (eq br) tr -> - (tree_contains tg (of_branch br) <-> tree_contains tg' (of_branch br)). - Proof. - intros Rel Rel' br ExBr. - destruct (decide (tree_contains tg (of_branch br))) as [Ex|nEx]. - all: destruct (decide (tree_contains tg' (of_branch br))) as [Ex'|nEx']. - all: try tauto. - all: exfalso. - - enough (tree_contains tg' (of_branch br)) by contradiction. - rewrite /StrictParentChildIn every_subtree_eqv_universal in Rel. - pose proof (proj1 (exists_node_iff_exists_root _ _) Ex) as WitnessSubtree. - rewrite exists_subtree_eqv_existential in WitnessSubtree. - destruct WitnessSubtree as [br' [ExBr' TgRoot]]. - assert (exists_subtree (eq br') tr) as ExBr'' by (eapply exists_subtree_transitive; eauto). - specialize (Rel br' ExBr'' TgRoot). - eapply exists_node_transitive. - + eassumption. - + simpl in TgRoot. - destruct br' as [[]]; simpl in *. - right; right; assumption. - - enough (tree_contains tg (of_branch br)) by contradiction. - rewrite /StrictParentChildIn every_subtree_eqv_universal in Rel'. - pose proof (proj1 (exists_node_iff_exists_root _ _) Ex') as WitnessSubtree. - rewrite exists_subtree_eqv_existential in WitnessSubtree. - destruct WitnessSubtree as [br' [ExBr' TgRoot]]. - assert (exists_subtree (eq br') tr) as ExBr'' by (eapply exists_subtree_transitive; eauto). - specialize (Rel' br' ExBr'' TgRoot). - eapply exists_node_transitive. - + eassumption. - + simpl in TgRoot. - destruct br' as [[]]; simpl in *. - right; right; assumption. - Qed. - - Lemma involution_of_branch - {X} {data : X} {tr1 tr2} - : branch data tr1 tr2 = of_branch (data, tr1, tr2). - Proof. reflexivity. Qed. - - Lemma strict_parent_self_impossible - {tg tr} : - tree_contains tg tr -> - StrictParentChildIn tg tg tr -> - False. - Proof. - intros Ex Strict. - induction tr as [|? ? IHtr1 ? IHtr2]; [inversion Ex|]. - inversion Strict as [Strict0 [Strict1 Strict2]]. - inversion Ex as [Ex0 | [Ex1 | Ex2]]. - - apply IHtr2. - + apply Strict0. assumption. - + assumption. - - apply IHtr1; assumption. - - apply IHtr2; assumption. - Qed. - - Lemma mutual_strict_parent_child_impossible - {tg tg' tr} : - tree_contains tg tr -> - tree_contains tg' tr -> - StrictParentChildIn tg tg' tr -> - StrictParentChildIn tg' tg tr -> - False. - Proof. - intros Ex Ex' Rel Rel'. - enough (StrictParentChildIn tg tg tr). - + eapply strict_parent_self_impossible. - * exact Ex. - * assumption. - + eapply StrictParentChild_transitive; eassumption. - Qed. - - Lemma mutual_parent_child_implies_equal - {tg tg' tr} : - tree_contains tg tr -> - tree_contains tg' tr -> - ParentChildIn tg tg' tr -> - ParentChildIn tg' tg tr -> - tg' = tg. - Proof. - rewrite /ParentChildIn. - intros Ex Ex'. - intros [|StrictRel]; [auto|]. - intros [|StrictRel']; [auto|]. - exfalso. - eapply mutual_strict_parent_child_impossible. - + exact Ex. - + exact Ex'. - + assumption. - + assumption. - Qed. - - Lemma rel_this_antisym - {tr tg tg'} : - tree_contains tg tr -> - tree_contains tg' tr -> - rel_dec tr tg tg' = Child This -> tg = tg'. - Proof. - rewrite /rel_dec. - remember (decide (ParentChildIn tg tg' tr)) as Rel. - remember (decide (ParentChildIn tg' tg tr)) as Rel'. - destruct Rel; destruct Rel'. - all: try (intro; discriminate). - intros Ex Ex' _. - eapply mutual_parent_child_implies_equal; eauto. - Qed. - - Lemma rel_dec_refl tr tg : - rel_dec tr tg tg = Child This. - Proof. - rewrite /rel_dec. - rewrite decide_True; [|left; reflexivity]. - rewrite decide_True; [|left; reflexivity]. - reflexivity. - Qed. - - Lemma child_of_this_is_foreign_for_cousin - {tr tg_this tg_cous tg_child} : - tree_unique tg_this tr -> - tree_unique tg_cous tr -> - tree_unique tg_child tr -> - rel_dec tr tg_this tg_cous = Foreign Cousin -> - (if rel_dec tr tg_child tg_this is Child _ then True else False) -> - rel_dec tr tg_child tg_cous = Foreign Cousin. - Proof. - intros Ex_this Ex_cous Ex_child. - intros Rel_this_cous Rel_child_this_Foreign. - destruct (rel_dec _ tg_child _) as [|pos] eqn:Rel_child_this; [contradiction|]. - destruct pos. - + rewrite /rel_dec in Rel_this_cous, Rel_child_this |- *. - repeat destruct (decide (ParentChildIn _ _ _)); try discriminate. - - enough (ParentChildIn tg_this tg_cous tr) by contradiction. - eapply ParentChild_transitive; eassumption. - - exfalso. - eapply cousins_have_disjoint_children with (tg1 := tg_this) (tg2 := tg_cous). - * eassumption. - * assumption. - * assumption. - * rewrite /rel_dec. - rewrite decide_False; [|eassumption]. - rewrite decide_False; [|eassumption]. - reflexivity. - * eassumption. - * eassumption. - - enough (ParentChildIn tg_this tg_cous tr) by contradiction. - eapply ParentChild_transitive; eassumption. - - reflexivity. - + rewrite (rel_this_antisym _ _ Rel_child_this); first assumption. - all: apply unique_exists; assumption. - Qed. - - Lemma cousin_write_for_initialized_protected_nondisabled_is_ub - {it l acc_tg tr range tg b} - (Lookup : tree_lookup tr tg it) - (Protected : protector_is_active (iprot it) C) - (IsInit : initialized (item_lookup it l) = PermInit) - (IsCousin : rel_dec tr acc_tg tg = Foreign Cousin) - (InRange : range'_contains range l) - : ~ is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm AccessWrite)) C acc_tg range tr). - Proof. - intro Absurd. - rewrite -apply_access_success_condition in Absurd. - rewrite every_node_eqv_universal in Absurd. - specialize (Absurd it). - assert (itag it = tg) as Tg. { eapply tree_determined_specifies_tag; apply Lookup. } - rewrite Tg in Absurd. - rewrite IsCousin in Absurd. - rewrite /item_apply_access /permissions_apply_range' in Absurd. - rewrite is_Some_ignore_bind in Absurd. - rewrite -mem_apply_range'_success_condition in Absurd. - rewrite bool_decide_eq_true_2 in Absurd; [|auto]. - enough (is_Some (apply_access_perm AccessWrite (Foreign Cousin) true (item_lookup it l))) as Absurd'. - - rewrite /apply_access_perm in Absurd'. - destruct (item_lookup _ _) as [[] [[]| | | |]], b; simpl in Absurd'. - all: try inversion Absurd'; discriminate. - - rewrite /item_lookup. setoid_rewrite maybe_non_children_only_no_effect in Absurd; last done. - apply Absurd; [|done]. - eapply exists_determined_exists; apply Lookup. - Qed. - - Lemma pseudo_conflicted_allows_more_access - {tr1 tr2 tg l confl1 confl2 kind rel isprot ini acc_tg range it1 b} - (* Main hypotheses *) - (Confl1 : pseudo_conflicted tr1 tg l confl1) - (Confl2 : pseudo_conflicted tr2 tg l confl2) - (AccEx : tree_unique acc_tg tr1) - (TgEx : tree_unique tg tr1) - (* Auxiliary stuff to bind the local access to the global success for the pseudo conflicted case *) - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GlobalSuccess : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1)) - (ProtSpec : isprot = bool_decide (protector_is_active (iprot it1) C)) - (RelSpec : rel = rel_dec tr1 acc_tg tg) - (PermSpec : item_lookup it1 l = {| initialized := ini; perm := Reserved confl1 |}) - (InRange : range'_contains range l) - : is_Some - (apply_access_perm kind rel isprot - {| initialized := ini; perm := Reserved confl1 |}) - -> is_Some - (apply_access_perm kind rel isprot - {| initialized := ini; perm := Reserved confl2 |}). - Proof. - rewrite /apply_access_perm /apply_access_perm_inner; simpl. - (* Most cases are by reflexivity. *) - destruct kind, rel; simpl. - all: destruct ini, isprot; simpl; try auto. - all: inversion Confl1 as [|?? RelCous LookupCous]. - all: inversion Confl2. - all: subst; simpl; try auto. - (* Once we get reflexivity out of the way we are left with the accesses - where there is UB in the target because of the conflicted. - We now need to prove that actually there is also UB in the source, - just not _here_, instead it occured at the cousin that creates the conflict. *) - all: exfalso. - (* FIXME: here we need a lemma that shows - 1. a Child/This access for tg is Foreign for tg_cous who is Cousin of tg - 2. a Foreign access for such tg_cous is UB globally. - We can indeed check that in all of the following cases we have - rel = This or rel = Child and kind = AccessWrite. *) - all: eapply cousin_write_for_initialized_protected_nondisabled_is_ub. - all: try exact GlobalSuccess. - all: try eassumption. - all: eapply child_of_this_is_foreign_for_cousin. - all: try apply RelCous. - all: try assumption. - all: try rewrite -RelSpec; auto. - all: apply GloballyUnique1; apply LookupCous. - Qed. - - Lemma pseudo_conflicted_post_prot_allows_more_access - {tr1 tg l confl1 confl2 kind rel isprot ini acc_tg range it1 b} - (* Main hypotheses *) - (AccEx : tree_unique acc_tg tr1) - (TgEx : tree_unique tg tr1) - (* Auxiliary stuff to bind the local access to the global success for the pseudo conflicted case *) - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GlobalSuccess : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1)) - (NoProp : ¬ protector_is_active (iprot it1) C) - (ProtSpec : isprot = bool_decide (protector_is_active (iprot it1) C)) - (RelSpec : rel = rel_dec tr1 acc_tg tg) - (PermSpec : item_lookup it1 l = {| initialized := ini; perm := Reserved confl1 |}) - (InRange : range'_contains range l) - : is_Some - (apply_access_perm kind rel isprot - {| initialized := ini; perm := Reserved confl1 |}) - -> is_Some - (apply_access_perm kind rel isprot - {| initialized := ini; perm := Reserved confl2 |}). - Proof. - rewrite /apply_access_perm /apply_access_perm_inner; simpl. - rewrite bool_decide_false in ProtSpec; last done. subst isprot. - (* Most cases are by reflexivity. *) - destruct kind, rel; simpl. - all: destruct ini; simpl; try auto. - all: subst; simpl; try auto. - all: destruct confl1, confl2. - all: subst; simpl; try auto. - Qed. - - Lemma pseudo_disabled_allows_more_access - {tr1 tr2 tg l p1 p2 kind rel isprot acc_tg range it1 b} - (* Main hypotheses *) - (Confl1 : pseudo_disabled tr1 tg l p1 (iprot it1)) - (Confl2 : pseudo_disabled tr2 tg l p2 (iprot it1)) - (AccEx : tree_unique acc_tg tr1) - (TgEx : tree_unique tg tr1) - (* Auxiliary stuff to bind the local access to the global success for the pseudo conflicted case *) - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GlobalSuccess : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1)) - (ProtSpec : isprot = bool_decide (protector_is_active (iprot it1) C)) - (RelSpec : rel = rel_dec tr1 acc_tg tg) - (PermSpec : item_lookup it1 l = {| initialized := PermLazy; perm := p1 |}) - (InRange : range'_contains range l) - : is_Some - (apply_access_perm kind rel isprot - {| initialized := PermLazy; perm := p1 |}) - -> is_Some - (apply_access_perm kind rel isprot - {| initialized := PermLazy; perm := p2 |}). - Proof. - rewrite /apply_access_perm /apply_access_perm_inner; simpl. - destruct rel; last first. - - inversion Confl1 as [H1 H2|tg_cs it_cs X1 X2 Hcs Hlu Hluact Hpp XX X3]; simplify_eq. - 1: destruct kind; simpl; intros [? [=]]. - exfalso. eapply apply_access_success_condition in GlobalSuccess. - eapply every_node_eqv_universal in GlobalSuccess. - 2: eapply tree_lookup_to_exists_node, Hlu. - rewrite /item_apply_access /permissions_apply_range' in GlobalSuccess. - erewrite is_Some_ignore_bind in GlobalSuccess. - eapply mem_apply_range'_success_condition in GlobalSuccess. - 2: exact InRange. - rewrite /rel_dec in GlobalSuccess. - assert (itag it_cs = tg_cs) as Hcstg by by eapply tree_lookup_correct_tag. - rewrite decide_False in GlobalSuccess. - 2: { intros HPC. eapply cousins_have_disjoint_children. - 4: exact Hcs. 2: done. 1: exact AccEx. - 1: eapply GloballyUnique1, Hlu. 2: by subst. - rewrite /rel_dec in RelSpec. destruct decide in RelSpec; done. } - rewrite decide_False in GlobalSuccess. - 2: { intros HPC. rewrite /rel_dec in RelSpec Hcs. - destruct decide as [HP1|?] in RelSpec; try done. - destruct decide as [?|HnP1] in Hcs; try done. - destruct decide as [?|HnP2] in Hcs; try done. - eapply HnP2. eapply ParentChild_transitive. - 1: exact HP1. subst. done. } - rewrite /item_lookup in Hpp. - rewrite Hpp bool_decide_true // in GlobalSuccess. - rewrite maybe_non_children_only_no_effect // in GlobalSuccess. - destruct kind; destruct GlobalSuccess as [x [=]]. - - rewrite /=. intros _. destruct kind, isprot, p2 as [[]| | | |]; simpl; done. - Qed. - - (* FIXME: move this elsewhere *) - Lemma if_fun_absorb_args {X Y} {b : bool} {x : X} {f g : X -> Y} : - (if b then f else g) x = if b then f x else g x. - Proof. destruct b; reflexivity. Qed. - - Lemma rel_dec_child_transitive - {tr tg1 tg2 tg3 incl1 incl2} - : rel_dec tr tg1 tg2 = Child incl1 -> - rel_dec tr tg2 tg3 = Child incl2 -> - exists incl3, rel_dec tr tg1 tg3 = Child incl3. - Proof. - intros Rel12 Rel23. - unfold rel_dec in *. - destruct (decide (ParentChildIn tg2 tg1 tr)); last congruence. - destruct (decide (ParentChildIn tg3 tg2 tr)); last congruence. - assert (ParentChildIn tg3 tg1 tr) by (eapply ParentChild_transitive; eassumption). - eexists. - destruct (decide (ParentChildIn tg3 tg1 tr)); last contradiction. - f_equal. - Qed. - - Lemma frozen_in_practice_rejects_child_write - {tr tg witness l b acc_tg range} - (InRange : range'_contains range l) - (GloballyUnique : forall tg, tree_contains tg tr -> tree_unique tg tr) - (Frz : frozen_in_practice tr tg witness l) - (Acc : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm AccessWrite)) C acc_tg range tr)) - (Rel : exists x, rel_dec tr acc_tg tg = Child x) - : False. - Proof. - inversion Frz as [it_witness ? Rel' Lkup Perm]. - rewrite -apply_access_success_condition in Acc. - rewrite every_node_iff_every_lookup in Acc. 2: { - intros tg0 Ex0. apply unique_lookup. apply GloballyUnique. assumption. - } - specialize (Acc _ _ Lkup). - assert (exists x, rel_dec tr acc_tg witness = Child x) as FullRel. 1: { - destruct Rel as [? Rel]. - eapply rel_dec_child_transitive; eassumption. - } - destruct FullRel as [? FullRel]. - assert (itag it_witness = witness) as WitnessTg. { - eapply tree_determined_specifies_tag; apply Lkup. - } - rewrite WitnessTg FullRel in Acc. - unfold item_apply_access, maybe_non_children_only in Acc. - unfold is_Some in Acc. - destruct Acc as [? Acc]. - rewrite bind_Some in Acc. - destruct Acc as [? [Acc Res]]. - injection Res; clear Res; intros; subst. - unfold permissions_apply_range' in Acc. - pose proof (mk_is_Some _ _ Acc) as AccSome; clear Acc. - rewrite -mem_apply_range'_success_condition in AccSome. - specialize (AccSome l InRange). - do 4 rewrite if_fun_absorb_args in AccSome. - unfold nonchildren_only in AccSome. - rewrite Tauto.if_same in AccSome. - unfold apply_access_perm, apply_access_perm_inner in AccSome. - rewrite Perm in AccSome. - simpl in AccSome. - inversion AccSome; congruence. - Qed. - - Lemma loc_eq_up_to_C_allows_more_access - {d tr1 tr2 tg it1 it2 l kind acc_tg range b} - (Tg1 : itag it1 = tg) - (Tg2 : itag it2 = tg) - (UnqAcc : tree_unique acc_tg tr1) - (UnqAcc2 : tree_unique acc_tg tr2) - (Ex1 : tree_unique tg tr1) - (Ex2 : tree_lookup tr2 tg it2) - (SameRel : forall tg tg', rel_dec tr1 tg tg' = rel_dec tr2 tg tg') - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (ParentsMoreInit : parents_more_init tr2) - (GlobalSuccess : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1)) - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (InRange : range'_contains range l) - (Hrestrict : kind = AccessWrite → d = Forwards) - : - loc_eq_up_to_C tr1 tr2 tg d it1 it2 l -> - is_Some (maybe_non_children_only b (apply_access_perm kind) (rel_dec tr1 acc_tg (itag it1)) - (bool_decide (protector_is_active (iprot it1) C)) - (item_lookup it1 l)) - -> - is_Some (maybe_non_children_only b (apply_access_perm kind) (rel_dec tr2 acc_tg (itag it2)) - (bool_decide (protector_is_active (iprot it2) C)) - (item_lookup it2 l)). - Proof. - intros EqC Acc1. - inversion EqC as [EqProt EqCLookup]. - inversion EqCLookup as - [perm Lookup EqLookup - |??? Prot Confl1 Confl2 Lookup1 Lookup2 - |??? Prot Lookup1 Lookup2 - |p1 p2 Confl1 Confl2 Lookup1 Lookup2 - |witness_tg ?? Dis1 Dis2 Lookup1 Lookup2 - |ini ?? witness_tg Frz Lookup1 Lookup2 - |p1 p2 ini Hd Lookup1 Lookup2 - ]. - - rewrite Tg2 -Tg1. - rewrite -SameRel. - rewrite -EqProt. - apply Acc1. - - rewrite Lookup2. - rewrite -Lookup1 in Acc1. - edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]. - 2: by erewrite Heq. - rewrite Heq. rewrite -Lookup2. - eapply (pseudo_conflicted_allows_more_access Confl1 Confl2 UnqAcc Ex1 GloballyUnique1 GlobalSuccess). - + rewrite -EqProt; reflexivity. - + rewrite SameRel -Tg2 //=. - + rewrite /item_lookup Lookup1 //=. - + exact InRange. - + rewrite Tg1 -Tg2 SameRel EqProt Heq // in Acc1. - - rewrite Lookup2. - rewrite -Lookup1 in Acc1. - edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]. - 2: by erewrite Heq. - rewrite Heq. rewrite -Lookup2. - eapply (pseudo_conflicted_post_prot_allows_more_access UnqAcc Ex1 GloballyUnique1 GlobalSuccess). - + done. - + rewrite -EqProt; reflexivity. - + rewrite SameRel -Tg2 //=. - + symmetry. apply Lookup1. - + exact InRange. - + rewrite Tg1 -Tg2 SameRel EqProt Heq // in Acc1. - - rewrite Lookup2. - rewrite -Lookup1 in Acc1. - edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]. - 2: by erewrite Heq. - rewrite Heq. rewrite -Lookup2. - eapply (pseudo_disabled_allows_more_access Confl1 Confl2 UnqAcc Ex1 GloballyUnique1 GlobalSuccess). - + rewrite -EqProt; reflexivity. - + rewrite SameRel -Tg2 //=. - + rewrite /item_lookup Lookup1 //=. - + exact InRange. - + rewrite Tg1 -Tg2 SameRel EqProt Heq // in Acc1. - - (* FIXME: there has to be a shorter proof *) - (* This has to be a foreign access *) - destruct (rel_dec tr1 acc_tg (itag it1)) eqn:AccRel; last first. - + (* If it's a child access then it's also a child access for the Disabled parent. *) - inversion Dis1 as [it_witness ? RelWitness LookupWitness DisWitnessPre]. - destruct (decide (perm (item_lookup it_witness l) = Disabled)) as [Hdis|HNonDis]; simplify_eq. - * rewrite <- apply_access_success_condition in GlobalSuccess. - rewrite every_node_iff_every_lookup in GlobalSuccess. 2: { - intros tg0 Ex0. apply unique_lookup. apply GloballyUnique1. assumption. - } - specialize (GlobalSuccess _ _ LookupWitness). - pose proof (tree_determined_specifies_tag _ _ _ (proj1 LookupWitness) (proj2 LookupWitness)) - as WitnessTg. - subst witness_tg. - assert (match rel_dec tr1 acc_tg (itag it_witness) with - | Child _ => True - | Foreign _ => False - end - ). { - unfold rel_dec in RelWitness. - destruct (decide _); last discriminate. - unfold rel_dec in AccRel. - destruct (decide _); last discriminate. - unfold rel_dec. - destruct (decide (ParentChildIn (itag it_witness) acc_tg tr1)) as [|WitnessAccRel]; first done. - apply WitnessAccRel. - eapply ParentChild_transitive. - + eassumption. - + eassumption. - } - destruct (rel_dec _ acc_tg (itag it_witness)); first contradiction. - (* Finally we have all the ingredients of the contradiction *) - rewrite /item_apply_access in GlobalSuccess. - destruct GlobalSuccess as [? GlobalSuccess]. - rewrite bind_Some in GlobalSuccess. - destruct GlobalSuccess as [tmp_perms [PermissionsApply Wrapper]]. - injection Wrapper; clear Wrapper; intros; subst. - rewrite /permissions_apply_range' in PermissionsApply. - pose proof (proj2 (mem_apply_range'_success_condition _ _ _) (mk_is_Some _ _ PermissionsApply)) - as PermissionApply. - specialize (PermissionApply l InRange). - unfold item_lookup in Hdis. - rewrite /maybe_non_children_only in PermissionApply. - rewrite /nonchildren_only /= in PermissionApply. - repeat rewrite if_fun_absorb_args in PermissionApply. - rewrite Tauto.if_same in PermissionApply. - rewrite /apply_access_perm /= in PermissionApply. - destruct PermissionApply as [tmp_lazy PermissionApply]. - rewrite bind_Some in PermissionApply. - destruct PermissionApply as [tmp_perm [ApplyAccessInner ValidateProt]]. - rewrite Hdis in ApplyAccessInner. - rewrite /apply_access_perm_inner in ApplyAccessInner. - case_match; discriminate. - * inversion DisWitnessPre as [HX DisWitness|lp HDis Hlookup HX]; simplify_eq. - 1: rewrite -DisWitness in HNonDis; done. - inversion Hlookup as [HX1 HX2|tg_w2 it_w2 x1 x2 Hcs2 Hlu2 Hprot2 Hperm2 Hlp]; simplify_eq. - 1: rewrite -HX // in HNonDis. - rewrite <- apply_access_success_condition in GlobalSuccess. - rewrite every_node_iff_every_lookup in GlobalSuccess. 2: { - intros tg0 Ex0. apply unique_lookup. apply GloballyUnique1. assumption. - } - specialize (GlobalSuccess _ _ Hlu2). - pose proof (tree_determined_specifies_tag _ _ _ (proj1 Hlu2) (proj2 Hlu2)) - as <-. - rewrite /rel_dec in RelWitness. - destruct decide as [HPC1|] in RelWitness; last done. clear RelWitness. - rewrite /rel_dec in AccRel. - destruct decide as [HPC2|] in AccRel; last done. clear AccRel. - rewrite /rel_dec decide_False in GlobalSuccess; last first. - { intros HH. exfalso. eapply cousins_have_disjoint_children. 4: exact Hcs2. - 5: exact HH. 4: eapply ParentChild_transitive; eassumption. - 1: done. all: eapply GloballyUnique1. 2: eapply Hlu2. eapply LookupWitness. } - rewrite decide_False in GlobalSuccess; last first. - { intros HH. rewrite /rel_dec in Hcs2. - destruct decide as [|HHH] in Hcs2; first done. - destruct decide as [|HHH2] in Hcs2; first done. - eapply HHH2. do 3 (eapply ParentChild_transitive; first done). by left. } - exfalso. rewrite /item_apply_access in GlobalSuccess. - rewrite is_Some_ignore_bind in GlobalSuccess. - eapply mem_apply_range'_success_condition in GlobalSuccess. 2: done. - rewrite maybe_non_children_only_no_effect // in GlobalSuccess. - rewrite /item_lookup in Hperm2. rewrite Hperm2 in GlobalSuccess. - rewrite bool_decide_true // in GlobalSuccess. - destruct kind; cbv in GlobalSuccess; by destruct GlobalSuccess. - + rewrite <- EqProt. - destruct (bool_decide (protector_is_active (iprot it1) C)) eqn:Heq; last first. - { rewrite Tg2 -Tg1 -SameRel AccRel. - rewrite /maybe_non_children_only /nonchildren_only. - repeat rewrite if_fun_absorb_args. - repeat case_match; first done. - all: rewrite /apply_access_perm /apply_access_perm_inner //=. - all: repeat case_match; done. } - rewrite Tg2 -Tg1 -SameRel AccRel. - rewrite /maybe_non_children_only /nonchildren_only. - repeat rewrite if_fun_absorb_args. - inversion Dis2 as [it_witness ? RelWitness LookupWitness DisWitnessPre]. - (* we are protected. this means we are not initalized by state_wf *) - assert (initialized (item_lookup it2 l) = PermLazy) as HH. - 1: inversion DisWitnessPre as [HX DisWitness|lp HX HDis Hlookup]; simplify_eq. - { specialize (ProtParentsNonDis witness_tg). eapply every_child_ParentChildIn in ProtParentsNonDis. - 2: done. 2: eapply GloballyUnique2, LookupWitness. 2: eapply LookupWitness. 2: eapply GloballyUnique2, Ex2. - 2: rewrite /rel_dec in RelWitness; by destruct (decide (ParentChildIn witness_tg (itag it1) tr2)). - setoid_rewrite every_node_eqv_universal in ProtParentsNonDis. - ospecialize (ProtParentsNonDis it2 _ _). - 1: eapply exists_determined_exists; eapply Ex2. 1: by eapply tree_lookup_correct_tag. - rewrite /item_protected_all_parents_not_disabled in ProtParentsNonDis. - ospecialize (ProtParentsNonDis l). destruct (initialized (item_lookup it2 l)); last done. - rewrite -EqProt -DisWitness in ProtParentsNonDis. ospecialize (ProtParentsNonDis _ _). - 1: done. 1: by eapply bool_decide_eq_true_1. 1: done. } - { specialize (ParentsMoreInit witness_tg). eapply every_child_ParentChildIn in ParentsMoreInit. - 2: done. 2: eapply GloballyUnique2, LookupWitness. 2: eapply LookupWitness. 2: eapply GloballyUnique2, Ex2. - 2: rewrite /rel_dec in RelWitness; by destruct (decide (ParentChildIn witness_tg (itag it1) tr2)). - setoid_rewrite every_node_eqv_universal in ParentsMoreInit. - ospecialize (ParentsMoreInit it2 _ _). - 1: eapply exists_determined_exists; eapply Ex2. 1: by eapply tree_lookup_correct_tag. - ospecialize (ParentsMoreInit l). destruct (initialized (item_lookup it2 l)); last done. - rewrite -Hlookup in ParentsMoreInit. ospecialize (ParentsMoreInit _). - 1: done. 1: done. } - all: rewrite /apply_access_perm /apply_access_perm_inner HH //=. - all: repeat case_match; done. - - (* Frozen in practice case. - Before we do the usual manipulations we make both the left and right access use - the same [rel_dec] so that the [maybe_non_children_only] case distinction works - on both simultaneously. *) - rewrite SameRel in Acc1. - edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]. - 2: by erewrite Heq. (* Noop case, easy. *) - rewrite Heq. - rewrite Tg1 -Tg2 Heq in Acc1. - destruct kind, (rel_dec tr2 _ _) eqn:Rel. - + (* Foreign read is allowed *) - unfold apply_access_perm, apply_access_perm_inner. - repeat (case_match; simpl; try auto). - + (* Child read is allowed *) - unfold apply_access_perm, apply_access_perm_inner. - repeat (case_match; simpl; try auto). - + (* Foreign write is allowed, except when there is a protector. - Once we eliminate all other cases we'll have to prove that the protector is inactive by - using the left tree in which the access suceeded. *) - unfold apply_access_perm, apply_access_perm_inner. - repeat (case_match; simpl; try auto). - (* Now we have a goal that is definitely not provable, but we have gained - a hypothesis [protector_is_active] in the context. We can derive a contradiction. *) - all: exfalso. - all: unfold apply_access_perm, apply_access_perm_inner in Acc1. - all: repeat (case_match; simpl in Acc1; try auto). - all: try (inversion Acc1; congruence). - (* We have all the elements of the contradiction, but a bit of rewriting is necessary - to get them in a shape that is obviously conflicting. - At that point there are two kinds of goals - - some where the protector is active only on one side, solve them using [EqProt], - - others whene [initialized] returns inconsistent results, solve them by - unifying the same [ini] everywhere. *) - all: repeat multimatch goal with - | H : bool_decide _ = true |- _ => pose proof (bool_decide_eq_true_1 _ H); clear H - | H : bool_decide _ = false |- _ => pose proof (bool_decide_eq_false_1 _ H); clear H - | H : context [ iprot _ ] |- _ => rewrite EqProt in H - | |- _ => try contradiction - end. - all: assert (initialized (item_lookup it1 l) = ini) as Ini1 by (rewrite -Lookup1; done). - all: simpl in *; congruence. - + (* Child write is necessarily UB due to the Frozen parent *) - exfalso. - specialize (Hrestrict eq_refl). subst d. - eapply frozen_in_practice_rejects_child_write. 4: exact GlobalSuccess. - * eassumption. - * eassumption. - * eassumption. - * eexists. rewrite SameRel. rewrite -Tg2. apply Rel. - - rewrite -SameRel Tg2 -Tg1 -EqProt. edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]; - erewrite Heq in Acc1; erewrite Heq; clear Heq. 2: done. - rewrite -Lookup1 in Acc1. destruct kind. - + destruct d; (inversion Hd as [P Hprot|P Hnoprot]; subst P p1 p2; - [ rewrite bool_decide_eq_false_2 // in Acc1|-* - | rewrite bool_decide_eq_true_2 // in Acc1|-*]). - all: destruct (rel_dec tr1 acc_tg (itag it1)), ini. - all: rewrite /apply_access_perm /apply_access_perm_inner /= in Acc1|-*; done. - + specialize (Hrestrict eq_refl). subst d. - inversion Hd as [P Hprot|P Hnoprot]; subst P p1 p2. - 1: rewrite bool_decide_eq_false_2 // in Acc1|-*. - 2: rewrite bool_decide_eq_true_2 // in Acc1|-*. - all: destruct (rel_dec tr1 acc_tg (itag it1)), ini. - all: rewrite /apply_access_perm /apply_access_perm_inner /= in Acc1|-*; done. - Qed. - - Lemma item_eq_up_to_C_allows_more_access (b:bool) - {d tr1 tr2 tg it1 it2 kind acc_tg range} - (Tg1 : itag it1 = tg) - (Tg2 : itag it2 = tg) - (UnqAcc : tree_unique acc_tg tr1) - (UnqAcc2 : tree_unique acc_tg tr2) - (Ex1 : tree_unique tg tr1) - (Ex2 : tree_lookup tr2 tg it2) - (SameRel : forall tg tg', rel_dec tr1 tg tg' = rel_dec tr2 tg tg') - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (ParentsMoreInit : parents_more_init tr2) - (GlobalSuccess : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1)) - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (Hrestrict : kind = AccessWrite → d = Forwards) - : - item_eq_up_to_C tr1 tr2 tg d it1 it2 -> - is_Some (item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr1 acc_tg (itag it1)) range it1) -> - is_Some (item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr2 acc_tg (itag it2)) range it2). - Proof. - rewrite /item_apply_access /permissions_apply_range'. - rewrite is_Some_ignore_bind. - rewrite is_Some_ignore_bind. - intros EqC. - intro App1. - rewrite -mem_apply_range'_success_condition in App1. - rewrite -mem_apply_range'_success_condition. - intros l InRange. - specialize (App1 l InRange). - specialize (EqC l). - eapply (loc_eq_up_to_C_allows_more_access Tg1 Tg2 UnqAcc UnqAcc2 Ex1 Ex2 SameRel); done. - Qed. - - Lemma tree_equal_allows_more_access_maybe_nonchildren_only (b:bool) - {d tr1 tr2 kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (ParentsMoreInit : parents_more_init tr2) - (Hrestrict : kind = AccessWrite → d = Forwards) : - tree_equal d tr1 tr2 -> - tree_unique acc_tg tr1 -> - is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1) -> - is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr2). - Proof. - intros Eq UnqAcc Acc1. - apply apply_access_success_condition. - pose proof (proj2 (apply_access_success_condition _ _ _ _ _) Acc1) as Every1. - (* Get it into a more usable form *) - rewrite every_node_iff_every_lookup in Every1. - 2: eapply tree_equal_implies_globally_unique_1; eassumption. - rewrite every_node_iff_every_lookup. - 2: eapply tree_equal_implies_globally_unique_2; eassumption. - (* And now we can unfold the definitions more *) - intros tg it Lookup2. - pose proof Eq as EqCopy. - destruct EqCopy as [ExIff [SameRel Lookup]]. - destruct (tree_equal_transfer_lookup_2 Eq Lookup2) as [it1 [Lookup1 EqC]]. - eapply (item_eq_up_to_C_allows_more_access b). - - erewrite tree_determined_specifies_tag. 2,3: eapply Lookup1. reflexivity. - - erewrite tree_determined_specifies_tag. 2,3: eapply Lookup2. reflexivity. - - apply UnqAcc. - - eapply GloballyUnique2. destruct Eq as (H1&H2&H3). eapply H1. by eapply unique_exists. - - apply GloballyUnique1. apply Lookup1. - - done. - - eassumption. - - eapply ProtParentsNonDis. - - done. - - apply Acc1. - - exact GloballyUnique1. - - exact GloballyUnique2. - - done. - - done. - - eapply Every1; eassumption. - Qed. - - Lemma tree_equal_allows_more_access - {d tr1 tr2 kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (ParentsMoreInit : parents_more_init tr2) - (Hrestrict : kind = AccessWrite → d = Forwards) : - tree_equal d tr1 tr2 -> - tree_unique acc_tg tr1 -> - is_Some (memory_access kind C acc_tg range tr1) -> - is_Some (memory_access kind C acc_tg range tr2). - Proof. - by eapply (tree_equal_allows_more_access_maybe_nonchildren_only false). - Qed. - - Lemma tree_equal_allows_more_access_nonchildren_only - {d tr1 tr2 kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (ParentsMoreInit : parents_more_init tr2) - (Hrestrict : kind = AccessWrite → d = Forwards) : - tree_equal d tr1 tr2 -> - tree_unique acc_tg tr1 -> - is_Some (memory_access_nonchildren_only kind C acc_tg range tr1) -> - is_Some (memory_access_nonchildren_only kind C acc_tg range tr2). - Proof. - by eapply (tree_equal_allows_more_access_maybe_nonchildren_only true). - Qed. - - Lemma memory_access_same_rel_dec - {tr tr' acc cids acc_tg range} b - : memory_access_maybe_nonchildren_only b acc cids acc_tg range tr = Some tr' -> - forall tg tg', rel_dec tr tg tg' = rel_dec tr' tg tg'. - Proof. eapply access_same_rel_dec. Qed. - - Lemma access_preserves_pseudo_conflicted_activable (b:bool) - {tr tg l kind acc_tg range tr'} : - pseudo_conflicted tr tg l ResActivable -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr' -> - pseudo_conflicted tr' tg l ResActivable. - Proof. - intros PseudoC Acc. - inversion PseudoC as [|tg_cous it_cous cous_rel [cous_ex cous_det] cous_prot cous_nondis cous_init]. - destruct (apply_access_spec_per_node cous_ex cous_det Acc) - as (cous' & cous'_spec & cous'_ex & cous'_det). - symmetry in cous'_spec. - rewrite bind_Some in cous'_spec. - destruct cous'_spec as (perms' & perms'_spec & cous'_build). - injection cous'_build; intros; subst; clear cous'_build. - pose proof (mem_apply_range'_spec _ _ l _ _ perms'_spec) as effect_at_l. - destruct (decide _). - + (* within range. Big case analysis incoming. *) - destruct effect_at_l as (perm' & perm'_lookup & perm'_spec). - edestruct (maybe_non_children_only_effect_or_nop b (apply_access_perm kind) (rel_dec tr acc_tg (itag it_cous))) as [Heff|Heff]. - all: rewrite Heff in perm'_spec. - 1: rewrite bind_Some in perm'_spec; - destruct perm'_spec as (perm & perm_apply_inner & perm'_spec); - rewrite bind_Some in perm'_spec; - destruct perm'_spec as (perm_validated & perm_check_prot & perm'_spec). - all: pose proof perm'_spec as [= <-]. - all: (econstructor; [ - erewrite <- access_same_rel_dec; eassumption - | done - | done - | .. ]). - * rewrite /item_lookup /= perm'_lookup /=. - rewrite /item_lookup in cous_init. - destruct (iperm it_cous !! l) eqn:it_cous_defined. - all: rewrite it_cous_defined !cous_init in perm_check_prot. - all: rewrite bool_decide_eq_true_2 in perm_check_prot; last assumption. - all: destruct perm; try discriminate. - all: injection perm_check_prot; intros; subst; congruence. - * rewrite /item_lookup /= perm'_lookup /=. - rewrite /item_lookup in cous_init. - destruct (iperm it_cous !! l) eqn:it_cous_defined; - rewrite it_cous_defined cous_init //=. - * rewrite /item_lookup /= perm'_lookup //. - * rewrite /item_lookup /= perm'_lookup //. - + (* out of range is a lot easier *) - econstructor. - * erewrite <- access_same_rel_dec; eassumption. - * split; eassumption. - * eassumption. - * rewrite /item_lookup /= effect_at_l. assumption. - * rewrite /item_lookup /= effect_at_l. assumption. - Qed. - - Lemma access_preserves_pseudo_conflicted (b:bool) - {tr tg l kind acc_tg range conf tr'} : - pseudo_conflicted tr tg l conf -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr' -> - pseudo_conflicted tr' tg l conf. - Proof. - intros Hpc Haccess. destruct conf. - 2: by eapply access_preserves_pseudo_conflicted_activable. - inversion Hpc; by econstructor. - Qed. - - Lemma access_preserves_pseudo_disabled lp pr (b:bool) - {tr tg l kind acc_tg range tr'} : - pseudo_disabled tr tg l lp pr -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr' -> - pseudo_disabled tr' tg l lp pr. - Proof. - intros PseudoC Acc. - inversion PseudoC as [|tg_cous it_cous X1 X2 cous_rel [cous_ex cous_det] cous_nondis cous_init Hextra]; simplify_eq. - 1: econstructor 1. - destruct (apply_access_spec_per_node cous_ex cous_det Acc) - as (cous' & cous'_spec & cous'_ex & cous'_det). - symmetry in cous'_spec. - rewrite bind_Some in cous'_spec. - destruct cous'_spec as (perms' & perms'_spec & cous'_build). - injection cous'_build; intros; subst; clear cous'_build. - pose proof (mem_apply_range'_spec _ _ l _ _ perms'_spec) as effect_at_l. - destruct (decide _); last first. - + (* out of range is a lot easier *) - econstructor 2. - * erewrite <- access_same_rel_dec; eassumption. - * split; eassumption. - * eassumption. - * rewrite /item_lookup /= effect_at_l. assumption. - * done. - + (* within range. Big case analysis incoming. *) - destruct effect_at_l as (perm' & perm'_lookup & perm'_spec). - rewrite /item_lookup in cous_init. rewrite cous_init in perm'_spec. - rewrite bool_decide_true in perm'_spec. 2: done. - destruct b, kind, rel_dec as [[]|] in perm'_spec; cbv in perm'_spec. - all: try discriminate perm'_spec. - all: injection perm'_spec as <-. - all: econstructor 2; - [ erewrite <- access_same_rel_dec; eassumption - | split; eassumption - | done - | rewrite /item_lookup perm'_lookup /= // - | done - ]. - Qed. - - Lemma tree_apply_access_preserves_protector - {tr tr' tg acc_tg kind range b it it'} - (Lookup : tree_lookup tr tg it) - (Lookup' : tree_lookup tr' tg it') - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : iprot it' = iprot it. - Proof. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it'' [Spec'' [Ex'' Det'']]]. - symmetry in Spec''. - destruct (item_apply_access_preserves_metadata it it'' Spec'') as [?[]]. - rewrite (tree_determined_unify (proj1 Lookup') (proj2 Lookup') Det''). - done. - Qed. - - Lemma disabled_tree_apply_access_irreversible - {tr tr' tg acc_tg kind range loc b it} - (Lookup : tree_lookup tr tg it) - (Dis : perm (item_lookup it loc) = Disabled) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : exists it', - tree_lookup tr' tg it' - /\ perm (item_lookup it' loc) = Disabled. - Proof. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it' [Spec' [Ex' Det']]]. - exists it'. - split; first done. - symmetry in Spec'. - rewrite bind_Some in Spec'. destruct Spec' as [tmp [PermsApp Build]]. - injection Build; intros; subst; clear Build. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsApp) as LocSpec. - destruct (decide _). - + destruct LocSpec as [val [LookupVal SpecVal]]. - rewrite /item_lookup LookupVal /=. - rewrite /maybe_non_children_only /nonchildren_only in SpecVal. - repeat case_match. - 1: { injection SpecVal; intros; subst; done. } - all: rewrite /apply_access_perm /apply_access_perm_inner /= in SpecVal. - all: rewrite Dis /= in SpecVal. - all: repeat case_match; simpl in *; try congruence. - all: injection SpecVal; intros; subst; simpl; done. - + rewrite /item_lookup /= LocSpec Dis //. - Qed. - - Lemma is_disabled_tree_apply_access_child - {tr tr' tg acc_tg kind range loc b it} - (Lookup : tree_lookup tr tg it) - (Dis : is_disabled tr tg loc (item_lookup it loc) (iprot it)) - (Cont : tree_contains acc_tg tr) - (Uni : wf_tree tr) - (Inside : range'_contains range loc) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : ¬ ParentChildIn tg acc_tg tr. - Proof. - intros HPC. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it' [Spec' [Ex' Det']]]. - symmetry in Spec'. - rewrite bind_Some in Spec'. destruct Spec' as [tmp [PermsApp Build]]. - injection Build; intros; subst; clear Build. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsApp) as LocSpec. - eapply tree_lookup_correct_tag in Lookup as HH; subst tg. - rewrite decide_True // in LocSpec. - destruct LocSpec as (v&Hv&HHv). - destruct (decide (perm (item_lookup it loc) = Disabled)) as [Hdis|Hnondis]. - { rewrite /rel_dec decide_True // in HHv. - rewrite maybe_non_children_only_no_effect // in HHv. - rewrite /apply_access_perm /apply_access_perm_inner /= Hdis in HHv. - by destruct kind. } - inversion Dis as [X1 Hlu X2|lp X1 Hdis Hlu X2]; simplify_eq. - 1: rewrite -Hlu in Hnondis; done. - inversion Hdis as [X1 X2 X3|tg_cs it_cs X1 X2 Hcs Hlucs Hprotcs Hppcs Hcsfoo X3 X4]; simplify_eq. - 1: rewrite -Hlu in Hnondis; done. - destruct (apply_access_spec_per_node (proj1 Hlucs) (proj2 Hlucs) Acc) as [itcs' [Speccs' Hlucs']]. - symmetry in Speccs'. - rewrite bind_Some in Speccs'. destruct Speccs' as [tmpcs [PermsAppcs [= <-]]]. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsAppcs) as LocSpeccs. - rewrite decide_True // in LocSpeccs. - destruct LocSpeccs as [valcs [Hvcs HHvcs]]. - rewrite /rel_dec in HHvcs. - eapply tree_lookup_correct_tag in Hlucs' as HH; subst tg_cs. - rewrite decide_False in HHvcs; last first. - { intros HnPCI1. eapply cousins_have_disjoint_children in Hcs. 5: done. 5: done. - 1: done. all: simpl; eapply Uni. 1: done. 1: apply Lookup. 1: eapply Hlucs. } - rewrite decide_False in HHvcs; last first. - { intros HnPCI1. - rewrite /rel_dec in Hcs. - destruct decide as [?|HNP2] in Hcs; first done. - destruct decide as [?|HNP3] in Hcs; first done. - eapply HNP3; simpl. eapply ParentChild_transitive. - 1: done. done. } - rewrite maybe_non_children_only_no_effect // in HHvcs. - rewrite bool_decide_true // in HHvcs. - rewrite /item_lookup in Hppcs. - rewrite Hppcs in HHvcs. destruct kind; done. - Qed. - - Lemma is_disabled_tree_apply_access_irreversible - {tr tr' tg acc_tg kind range loc b it} - (Lookup : tree_lookup tr tg it) - (Dis : is_disabled tr tg loc (item_lookup it loc) (iprot it)) - (Cont : tree_contains acc_tg tr) - (Uni : wf_tree tr) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : exists it', - tree_lookup tr' tg it' ∧ iprot it = iprot it' ∧ - is_disabled tr' tg loc (item_lookup it' loc) (iprot it'). - Proof. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it' [Spec' [Ex' Det']]]. - exists it'. - split; first done. - symmetry in Spec'. - rewrite bind_Some in Spec'. destruct Spec' as [tmp [PermsApp Build]]. - injection Build; intros; subst; clear Build. split; first done. - destruct (decide (perm (item_lookup it loc) = Disabled)) as [Hdis|Hnondis]. - { eapply disabled_tree_apply_access_irreversible in Hdis as (it'&Htr'&Hit'). 2-3: done. - eapply tree_determined_unify in Det'. 2: done. 2: apply Htr'. - destruct (item_lookup it' loc) as [[] pp] eqn:Hini; subst it'. - all: rewrite Hini. all: simpl in Hit'; subst pp. - 1: econstructor 1. 1: econstructor 2. econstructor 1. } - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsApp) as LocSpec. - inversion Dis as [X1 Hlu X2|lp X1 Hdis Hlu X2]; simplify_eq. - 1: rewrite -Hlu in Hnondis; done. - inversion Hdis as [X1 X2 X3|tg_cs it_cs X1 X2 Hcs Hlucs Hprotcs Hppcs Hcsfoo X3 X4]; simplify_eq. - 1: rewrite -Hlu in Hnondis; done. - destruct (apply_access_spec_per_node (proj1 Hlucs) (proj2 Hlucs) Acc) as [itcs' [Speccs' Hlucs']]. - symmetry in Speccs'. - rewrite bind_Some in Speccs'. destruct Speccs' as [tmpcs [PermsAppcs [= <-]]]. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsAppcs) as LocSpeccs. - destruct (decide _) as [In|Out]; last first. - + rewrite /item_lookup /= LocSpec. - rewrite /item_lookup in Hlu. rewrite -Hlu. - econstructor. eapply access_preserves_pseudo_disabled. 1: done. done. - + destruct LocSpec as [val [LookupVal SpecVal]]. - destruct LocSpeccs as [valcs [LookupValcs SpecValcs]]. - rewrite /rel_dec in SpecVal. - eapply tree_lookup_correct_tag in Lookup as HH; subst tg. - eapply tree_lookup_correct_tag in Hlucs' as HH; subst tg_cs. - rewrite decide_False in SpecVal. - 2: { eapply is_disabled_tree_apply_access_child. 6: done. 2: done. all: done. } - edestruct maybe_non_children_only_effect_or_nop as [Heff|Heff]; - erewrite Heff in SpecVal; clear Heff. - 2: { injection SpecVal as <-. simpl. - rewrite /item_lookup /= in Hlu|-*. - rewrite LookupVal /= -Hlu. - econstructor 2. eapply access_preserves_pseudo_disabled; last done. - done. } - rewrite /item_lookup in Hlu. rewrite -Hlu in SpecVal. - rewrite /apply_access_perm /apply_access_perm_inner most_init_comm /= in SpecVal. - destruct kind, bool_decide eqn:Hbdc, lp as [[]| | | |] eqn:Hpm in SpecVal. - all: simpl in SpecVal. all: try discriminate SpecVal. - all: injection SpecVal as <-. - all: rewrite /= /item_lookup /= LookupVal /=. - all: econstructor 2. - all: eapply access_preserves_pseudo_disabled; last done. - all: econstructor; [exact Hcs|exact Hlucs|exact Hprotcs|exact Hppcs|]. - all: intros [=]. - all: subst lp; eapply Hcsfoo; done. - Qed. - - Lemma create_child_irreversible - {tr tr' tg tg_old tg_new it pk im rk cid} - (Lookup : tree_lookup tr tg it) - (Fresh : tg_new ≠tg) - (Ins : create_child C tg_old tg_new pk im rk cid tr = Some tr') - : tree_lookup tr' tg it. - Proof. - pose proof Ins as (x&<-%new_item_has_tag&[= <-])%bind_Some. - destruct Lookup as [Ex Det]. split. - - apply insert_preserves_exists; assumption. - - apply insert_true_preserves_every; last assumption. - intro SameTg. done. - Qed. - - Definition becomes_frozen (kind : access_kind) (range : Z * nat) (loc : Z) (b:bool) tr acc_tg it_tg: Prop := - if decide (range'_contains range loc) then kind = AccessRead ∨ (∃ k, b = true ∧ rel_dec tr acc_tg it_tg = Foreign (Parent k)) else True. - Definition becomes_disabled (kind : access_kind) (range : Z * nat) (loc : Z) (b:bool) tr acc_tg it_tg: Prop := - if decide (range'_contains range loc) then kind = AccessWrite ∧ (∃ f, rel_dec tr acc_tg it_tg = Foreign f ∧ ∀ p, f = Parent p → b = false) else False. - - Lemma becomes_not_both kind range loc b tr acc_tg it_tg : - becomes_frozen kind range loc b tr acc_tg it_tg → - becomes_disabled kind range loc b tr acc_tg it_tg → - False. - Proof. - intros H1 H2. - rewrite /becomes_frozen /becomes_disabled in H1,H2. - destruct decide. 2: done. - destruct H2 as (->&f&Hff&Hfb). - destruct H1 as [[=]|(k&->&Hk)]. - rewrite Hk in Hff. simplify_eq. - by specialize (Hfb _ eq_refl). - Qed. - - Lemma frozen_tree_apply_access_irreversible - {tr tr' tg acc_tg kind range loc b it} - (Lookup : tree_lookup tr tg it) - (Frz : (item_lookup it loc).(perm) = Frozen) - (Ini : (item_lookup it loc).(initialized) = PermInit) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : exists it', - tree_lookup tr' tg it' - /\ let k := (item_lookup it' loc) in let bf := becomes_frozen kind range loc b tr acc_tg (itag it) in let bd := becomes_disabled kind range loc b tr acc_tg (itag it) in - k.(initialized) = PermInit - /\ (k.(perm) = Frozen ∧ bf ∨ (k.(perm) = Disabled ∧ bd ∧ ¬ protector_is_active it'.(iprot) C)). - Proof. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it' [Spec' [Ex' Det']]]. - exists it'. - split; first done. - symmetry in Spec'. - rewrite bind_Some in Spec'. destruct Spec' as [tmp [PermsApp Build]]. - intros k bf bd. - injection Build; intros; subst; clear Build. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsApp) as LocSpec. subst bf bd. rewrite /becomes_frozen /becomes_disabled. - destruct (decide _); last first. - + subst k. rewrite /item_lookup /= LocSpec Frz Ini //. split; first done. by left. - + destruct LocSpec as [val [LookupVal SpecVal]]. subst k. - rewrite /item_lookup LookupVal /=. - rewrite /maybe_non_children_only /nonchildren_only in SpecVal. - repeat case_match. - 1: { injection SpecVal; intros; subst; split; first done. left. split; first done. eauto. } - all: rewrite /apply_access_perm /apply_access_perm_inner /= in SpecVal. - all: rewrite Frz /= Ini /= in SpecVal. - all: repeat case_match; simpl in *; try congruence. - all: injection SpecVal; intros; subst; simpl; split; first done. - all: first [ left; split; first done; eauto | right; split; first done; split ]. - 2, 4: by eapply bool_decide_eq_false_1. - all: split; first done. - all: eexists; split; first done. - 1: intros ? [=]. done. - Qed. - - Lemma parent_has_perm_similarly_disabled_after_access - {pp tr tr' tg acc_tg kind range loc b it} - (Lookup : tree_lookup tr tg it) - (Frz : (item_lookup it loc).(perm) = pp) - (nRIM : pp ≠ReservedIM) - (Ini : (item_lookup it loc).(initialized) = PermInit) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : exists it', - tree_lookup tr' tg it' - /\ let k := (item_lookup it' loc) in let bd := becomes_disabled kind range loc b tr acc_tg (itag it) in - k.(initialized) = PermInit - /\ (bd → (k.(perm) = Disabled ∧ ¬ protector_is_active it'.(iprot) C)). - Proof. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it' [Spec' [Ex' Det']]]. - exists it'. - split; first done. - symmetry in Spec'. - rewrite bind_Some in Spec'. destruct Spec' as [tmp [PermsApp Build]]. - intros k bd. - injection Build; intros; subst; clear Build. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsApp) as LocSpec. subst bd. rewrite /becomes_disabled. - destruct (decide _); last first. - + subst k. rewrite /item_lookup /= LocSpec Ini //. - + destruct LocSpec as [val [LookupVal SpecVal]]. subst k. - rewrite /item_lookup LookupVal /=. - rewrite /maybe_non_children_only /nonchildren_only in SpecVal. - repeat case_match. - 1: { injection SpecVal; intros; subst; split; first done. intros (->&f&[= <-]&HH). by specialize (HH _ eq_refl). } - all: rewrite /apply_access_perm /apply_access_perm_inner /= in SpecVal. - all: rewrite /= Ini /= in SpecVal. - all: repeat case_match; simpl in *; try congruence. - all: injection SpecVal; intros; subst; simpl; split; first done. - all: intros (Heq1&Hf&Heq2&HHf); simplify_eq. - all: split; last try by eapply bool_decide_eq_false_1. - all: done. - Qed. - - Lemma disabled_in_practice_tree_apply_access_irreversible - {tr tr' tg acc_tg kind range witness loc b} - (Dis : disabled_in_practice tr tg witness loc) - (Cont : tree_contains acc_tg tr) - (Uni : wf_tree tr) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : disabled_in_practice tr' tg witness loc. - Proof. - inversion Dis as [?? Rel Lookup Perm]. - destruct (is_disabled_tree_apply_access_irreversible Lookup Perm Cont Uni Acc) as [it' [Lookup' Perm']]. - econstructor. - + erewrite <- access_same_rel_dec; eassumption. - + apply Lookup'. - + apply Perm'. - Qed. - - Lemma frozen_in_practice_tree_apply_access_irreversible - {tr tr' tg acc_tg kind range witness loc b} - (Frz : frozen_in_practice tr tg witness loc) - (Cont : tree_contains acc_tg tr) - (Uni : wf_tree tr) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : let bf := becomes_frozen kind range loc b tr acc_tg witness in - let bd := becomes_disabled kind range loc b tr acc_tg witness in - (frozen_in_practice tr' tg witness loc ∧ bf) ∨ (parent_has_perm Disabled tr' tg witness loc ∧ bd). - Proof. - inversion Frz as [it_witness incl Rel Lookup Perm Init]. - assert (itag it_witness = witness) as <- by by eapply tree_lookup_correct_tag. - destruct (frozen_tree_apply_access_irreversible Lookup Perm Init Acc) as [it' [Lookup' [Init' [[Perm' BF]|[Perm' [BF NoProt]]]]]]. - - left. split; last done. econstructor. - + erewrite <- access_same_rel_dec; eassumption. - + apply Lookup'. - + apply Perm'. - + apply Init'. - - right. split; last done. econstructor. - + erewrite <- access_same_rel_dec; eassumption. - + apply Lookup'. - + destruct (item_lookup it' loc) as [lp pp]; simpl in Init',Perm'; subst. done. - + destruct (item_lookup it' loc) as [lp pp]; simpl in Init',Perm'; subst. done. - Qed. - - Lemma parent_has_disabled_perm_is_pseudo_disabled tr tg witness loc : - parent_has_perm Disabled tr tg witness loc → - disabled_in_practice tr tg witness loc. - Proof. - inversion 1 as [it incl H0 H1 H2 H3]; simplify_eq. - econstructor. 1-2: done. - destruct (item_lookup it loc); simpl in H2,H3; simplify_eq. - econstructor 1. - Qed. - - Lemma parent_has_perm_similarly_disabled - {p tr tr' tg acc_tg kind range witness loc b} - (Frz : parent_has_perm p tr tg witness loc) - (nRIM : p ≠ReservedIM) - (Cont : tree_contains acc_tg tr) - (Uni : wf_tree tr) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : let bd := becomes_disabled kind range loc b tr acc_tg witness in - bd → parent_has_perm Disabled tr' tg witness loc. - Proof. - inversion Frz as [it_witness incl Rel Lookup Perm Init]. - assert (itag it_witness = witness) as <- by by eapply tree_lookup_correct_tag. - destruct (parent_has_perm_similarly_disabled_after_access Lookup Perm nRIM Init Acc) as [it' [Lookup' [Init' Perm']]]. - intros bd. subst bd. intros Hbd. specialize (Perm' Hbd) as (Hd&Hnoprot). - econstructor. - + erewrite <- access_same_rel_dec; eassumption. - + apply Lookup'. - + destruct (item_lookup it' loc) as [lp pp]; simpl in Init',Hd; subst. done. - + destruct (item_lookup it' loc) as [lp pp]; simpl in Init',Hd; subst. done. - Qed. - - Lemma if_same_guard_equal - {P Q : Prop} {T} {x y x' y' : T} `{Decision P} `{Decision Q} - (Iff : P <-> Q) - (Ex : x = x') - (Ey : y = y') - : (if decide P then x else y) = (if decide Q then x' else y'). - Proof. - repeat destruct (decide _); tauto. - Qed. - - Lemma disabled_in_practice_create_child_irreversible - {tr tr' tg tg_old tg_new pk im rk cid witness loc} - (Ne : tg_new ≠tg) - (Ne' : tg_new ≠witness) - (Nc : ¬ tree_contains tg_new tr) - (Dis : disabled_in_practice tr tg witness loc) - (Ins : create_child C tg_old tg_new pk im rk cid tr = Some tr') - : disabled_in_practice tr' tg witness loc. - Proof. - inversion Dis as [it_witness ? Rel Lookup Perm]. - econstructor. - - erewrite <-create_child_same_rel_dec. 1: exact Rel. 3: done. 1-2: done. - - eapply create_child_irreversible. - 1: done. 2: done. done. - - inversion Perm as [|lp X H1 H2 X2]; simplify_eq. 1: econstructor 1. - econstructor 2. inversion H1 as [|tgcs itcs X1 X2 H1' H2' H3 H4 H5 X3 X4]; simplify_eq. 1: econstructor 1. - destruct (decide (tgcs = tg_new)) as [->|Hne]. - { exfalso. eapply Nc, H2'. } - econstructor 2. - + erewrite <-create_child_same_rel_dec. 1: exact H1'. 3: done. 1-2: done. - + eapply create_child_irreversible. 1: exact H2'. 2: done. done. - + done. - + done. - + done. - Qed. - - Lemma frozen_in_practice_create_child_irreversible - {tr tr' tg tg_old tg_new pk im rk cid witness loc} - (Ne : tg_new ≠tg) - (Ne' : tg_new ≠witness) - (Frz : frozen_in_practice tr tg witness loc) - (Ins : create_child C tg_old tg_new pk im rk cid tr = Some tr') - : frozen_in_practice tr' tg witness loc. - Proof. - inversion Frz as [it_witness ? Rel Lookup Perm Ini]. - opose proof (create_child_irreversible Lookup Ne' Ins) as Lookup'. - econstructor. - + erewrite <- create_child_same_rel_dec; first eassumption. - - eassumption. - - eassumption. - - eassumption. - + apply Lookup'. - + done. - + done. - Qed. - - Lemma most_init_comm {i i'} : - most_init i i' = most_init i' i. - Proof. - unfold most_init. - repeat case_match; reflexivity. - Qed. - - Lemma most_init_noop {i} : - most_init i PermLazy = i. - Proof. - unfold most_init. - case_match; reflexivity. - Qed. - - Lemma most_init_absorb {i} : - most_init i PermInit = PermInit. - Proof. - unfold most_init. - case_match; reflexivity. - Qed. - - Lemma trees_equal_find_equal_tag_protected_initialized_not_disabled d trs1 trs2 it1 tg blk off: - each_tree_protected_parents_not_disabled C trs2 → - wf_trees trs2 → - trees_equal d trs1 trs2 → - trees_lookup trs1 blk tg it1 → - (initialized (item_lookup it1 off) = PermInit → perm (item_lookup it1 off) ≠Disabled) → - protector_is_active it1.(iprot) C → - ∃ it2, trees_lookup trs2 blk tg it2 ∧ - (initialized (item_lookup it2 off) = PermInit → perm (item_lookup it2 off) ≠Disabled) ∧ - protector_is_active it2.(iprot) C. - Proof. - intros Heach Hwf Heq (tr1&Htr1&Hit) Hperm Hactive. - specialize (Heq blk). rewrite Htr1 in Heq. inversion Heq as [x tr2 Heq' Hx Htr2|]. subst x. - destruct Heq' as (Heq1&Heq2&Heq3). - pose proof Hit as (Hitin&Hitdet). - specialize (Heq3 _ Hitin) as (it1'&it2&Hit1'&Hit2&Heqit). - assert (it1 = it1') as <-. - { eapply tree_determined_unify. 2: done. 1: done. apply Hit1'. } - exists it2. specialize (Heqit off) as (Hprotit&Hlocit). - split. 1: exists tr2; done. - rewrite -Hprotit. inversion Hlocit as [|e c1 c2 H H1 H2 H3 H4| | | | |p1 p2 ini H]; simplify_eq. - - done. - - rewrite -!H3 /= in Hperm. simpl. done. - - exfalso. done. - - done. - - split; last done. intros Hinit Hdis. - ospecialize (Heach _ _ _ tg). 1: symmetry; exact Htr2. - eapply every_child_ParentChildIn in Heach. 2: by eapply Hwf. 2,4: eapply Hwf; first done; eapply Hit2. - 2: eapply Hit2. 2: by left. - rewrite every_node_eqv_universal in Heach. ospecialize (Heach it2 _ _ off _ _ Hdis). - 1: eapply exists_determined_exists; eapply Hit2. 1: by eapply tree_lookup_correct_tag. - 1: done. 1: by rewrite -Hprotit. done. - - split; last done. simpl. done. - - split; last done. simpl. intros ->. destruct d; by inversion H. - Qed. - - Lemma tree_lookup_IsTag tr tg it : tree_lookup tr tg it → IsTag tg it. - Proof. - intros (H1 & H2). - eapply exists_node_eqv_existential in H1 as (it2 & Hit2 & Histag). - eapply every_node_eqv_universal in H2; last done. - by rewrite -H2. - Qed. - - Lemma tree_lookup_unique tr tg it1 it2 : tree_lookup tr tg it1 → tree_lookup tr tg it2 → it1 = it2. - Proof. - intros Hlu (H1 & H2). - eapply every_node_eqv_universal in H2; first apply H2. - 1: by eapply tree_lookup_IsTag. - eapply exists_determined_exists; first done. - apply Hlu. - Qed. - - Lemma tree_equal_transfer_item_non_disabled d tr1 tr2 tg it off : - protected_parents_not_disabled C tr1 → - no_active_cousins C tr1 → - (∀ tg, tree_contains tg tr1 → tree_unique tg tr1) → - tree_equal d tr1 tr2 → - tree_lookup tr1 tg it → - protector_is_active (iprot it) C ∧ perm (item_lookup it off) ≠Disabled ∧ initialized (item_lookup it off) = PermInit → - ∃ it2, tree_lookup tr2 tg it2 ∧ protector_is_active (iprot it2) C ∧ perm (item_lookup it2 off) ≠Disabled ∧ initialized (item_lookup it2 off) = PermInit. - Proof. - intros Hpnd Hnac Hunq (He1&He2&He3) Hlu (Hprot&Hndis&Hini). - destruct (He3 tg) as (it1&it2&Hlu1&Hlu2&Heq). - 1: eapply Hlu. - assert (it = it1) as -> by by eapply tree_lookup_unique. - exists it2. specialize (Heq off) as (Hproteq&Hiteq). split; first done. - split. 1: by rewrite -Hproteq. - inversion Hiteq as [pp1|ini1 confl1 confl2 HprotX HP1 HP2 Heq1 Heq2|ini1 confl1 confl2 HnoProt|p1 p2 HP1 HP2 Heq1 Heq2|wit_tg lp1 lp2 Hdip1 Hdip2 HiniX Heq1 Heq2|ini1 confl1 confl2 wit_tg HF Heq1 Heq2|p1 p2 ini Hd Heq1 Heq2]; simplify_eq. - - done. - - split; first done. rewrite -Heq1 /= in Hini. rewrite /= Hini //. - - rewrite -Heq1 in Hini. done. - - exfalso. - inversion Hdip1 as [itw p Hreldec Hluw Hdisw]. - rewrite /rel_dec in Hreldec. destruct decide; last done. - eapply tree_lookup_correct_tag in Hlu as HH. subst tg. - specialize (Hpnd wit_tg). eapply every_child_ParentChildIn in Hpnd. - 2: eapply Hunq. 2: eapply Hunq, Hluw. 2: eapply Hluw. 2: eapply Hunq, Hlu. - 2: done. - eapply every_node_eqv_universal in Hpnd. - 2: { eapply tree_lookup_to_exists_node. eapply Hlu. } - inversion Hdisw as [X1 HH X2|pp X2 Hdis Hlazy X5]; simplify_eq. - { unshelve eapply (Hpnd _ off); [done..|by rewrite -HH]. } - inversion Hdis as [X1 HH X2|tgcs itcs lp X1 Hcs Hlucs Hprotcs Hactcs HH X2 X3]; simplify_eq. - { unshelve eapply (Hpnd _ off). 1-3: done. rewrite -Hlazy. done. } - eapply Hnac. 2: eapply Hlucs. 1: eapply Hlu. 3: by erewrite Hactcs. - 2: right; split; done. - eapply child_of_this_is_foreign_for_cousin. 4: exact Hcs. - 1-3: eapply Hunq. 1: eapply Hluw. 1: eapply Hlucs. 1: eapply Hlu. - rewrite /rel_dec decide_True //. - - split; first done. rewrite -Heq1 /= in Hini. rewrite /= Hini //. - - rewrite -Heq1 /= in Hini Hndis. simplify_eq. split; last done. - simpl. destruct d; inversion Hd; done. - Qed. - - Lemma tree_equal_transfer_pseudo_conflicted d tr1 tr2 tg off confl : - protected_parents_not_disabled C tr1 → - no_active_cousins C tr1 → - (∀ tg, tree_contains tg tr1 → tree_unique tg tr1) → - tree_equal d tr1 tr2 → - pseudo_conflicted tr1 tg off confl → - pseudo_conflicted tr2 tg off confl. - Proof. - intros Hpnd Hnac Hunq (HH1&HH2&HH3) Hconfl. - inversion Hconfl as [|tg_cs it_cs Hcs Hlu Hprot Hperm Hini]; simplify_eq. - - econstructor 1. - - edestruct tree_equal_transfer_item_non_disabled as (it2&Hit2&Hprot2&Hndis2&Hini2). - 1: exact Hpnd. 1: exact Hnac. 1: exact Hunq. 1: split; done. 1: exact Hlu. - 1: split; done. - econstructor 2. 1: by erewrite <- HH2. 1: exact Hit2. - all: done. - Qed. - - Global Instance pseudo_disabled_dec tr tg off pp oprot : Decision (pseudo_disabled tr tg off pp oprot). - Proof. - destruct (decide (pp = Disabled)) as [->|Hne]. - 1: left; econstructor 1. - pose (P it_cs := let tg_cs := itag it_cs in - rel_dec tr tg tg_cs = Foreign Cousin ∧ - tree_item_determined tg_cs it_cs tr ∧ - protector_is_active (iprot it_cs) C ∧ - item_lookup it_cs off = mkPerm PermInit Active ∧ - match pp with ReservedIM => False | _ => True end). - assert (∀ it, Decision (P it)) as DecP. - { intros it. - rewrite /P. - do 4 (eapply and_dec; first eapply _). - destruct pp. - all: eapply _. } - destruct (decide (exists_node P tr)) as [HP|HnP]. - - left. eapply exists_node_eqv_existential in HP as (it&Htgit&H1&H2&H3&H4&H5). - econstructor 2. - 1: exact H1. 1: split. 2: exact H2. - 1: eapply exists_node_eqv_existential; exists it; done. - 1: done. 1: done. - 1: intros ->. done. - - right. intros Hdis. - induction Hdis as [|tg_cs it_cs lp Hlp H1 H2 H3 H4 H5]; first done. - eapply HnP. eapply exists_node_eqv_existential. - exists it_cs. split. 1: eapply tree_lookup_to_exists_node; done. - assert (itag it_cs = tg_cs) as <- by by eapply tree_lookup_correct_tag. - split; first done. - split; first eapply H2. - split; first done. - split; first done. - destruct lp as [| | | |]; try done. - Defined. - - Global Instance is_disabled_dec tr tg off lp oprot : Decision (is_disabled tr tg off lp oprot). - Proof. - destruct (decide (lp = mkPerm PermInit Disabled)) as [->|Hne]. - 1: left; econstructor 1. - destruct lp as [[] pp]. - 1: { right. intros HH. inversion HH. subst pp. done. } - destruct (decide (pseudo_disabled tr tg off pp oprot)) as [Hpd|Hnpd]. - 1: left; econstructor 2; done. - right. - intros HH. inversion HH; simplify_eq. - Qed. - - Lemma exists_node_to_tree_lookup tr itm - (GloballyUnique : forall tg, tree_contains tg tr -> tree_unique tg tr) : - exists_node (eq itm) tr → - tree_lookup tr (itag itm) itm. - Proof. - intros Hexi. assert (tree_contains (itag itm) tr) as Hcontain. - - eapply exists_node_increasing; first done. - eapply every_node_eqv_universal; intros ? _ <-. done. - - split; first done. - eapply GloballyUnique, unique_lookup in Hcontain as (it2 & Hit2). - enough (itm = it2) by by subst itm. - eapply every_node_eqv_universal in Hit2; first eapply Hit2. - all: done. - Qed. - - Lemma trees_equal_decide_disabled_in_practice tr tg off : - (∀ tg, tree_contains tg tr → tree_unique tg tr) → - tree_contains tg tr → - (∃ tgp itp, tree_lookup tr tgp itp ∧ is_disabled tr tgp off (item_lookup itp off) (iprot itp) ∧ ParentChildIn tgp tg tr ∧ - ∀ tgpp itpp, tree_lookup tr tgpp itpp → StrictParentChildIn tgpp tgp tr → ¬ is_disabled tr tgpp off (item_lookup itpp off) (iprot itpp)) - + (∀ tgp itp, tree_lookup tr tgp itp → ParentChildIn tgp tg tr → ¬ is_disabled tr tgp off (item_lookup itp off) (iprot itp)). - Proof. - intros Hunq H. - assert (Decision (exists_node (λ it, is_disabled tr (itag it) off (item_lookup it off) (iprot it) ∧ ParentChildIn (itag it) tg tr) tr)) as Hdec. - { eapply exists_node_dec. intros itx. eapply and_dec. 2: by eapply ParentChildIn_dec. apply _. } - destruct Hdec as [Hleft|Hright]. - - left. - edestruct (find_highest_parent_with_property (λ x, is_disabled tr (itag x) off (item_lookup x off) (iprot x) ∧ ParentChildIn (itag x) tg tr)) as (tgpp&Htgpp&Hppp). - { intros x. eapply and_dec. 2: by eapply ParentChildIn_dec. apply _. } - { done. } - { done. } - eapply exists_node_eqv_existential in Htgpp. destruct Htgpp as (itpp&Hitpp&(HHitpp1&HHitpp2)&<-). - eapply exists_node_to_tree_lookup in Hitpp. 2: done. - exists (itag itpp), itpp. do 3 (split; first done). - intros tgppp itppp Hitppp HSPppp Hdis. - eapply Hppp. 2: exact HSPppp. - eapply tree_lookup_correct_tag in Hitppp as Htg. subst tgppp. - eapply exists_node_eqv_existential. exists itppp. - split. 2: split_and!; try done. 1: by eapply tree_lookup_to_exists_node. - eapply ParentChild_transitive; [|exact HHitpp2]; right; done. - - right. intros tgp itp Hlu HPC Hdis. eapply tree_lookup_correct_tag in Hlu as Htg; subst tgp. - eapply Hright. eapply exists_node_eqv_existential. - eexists. split. 1: eapply tree_lookup_to_exists_node, Hlu. split; done. - Qed. - - Lemma item_eq_up_to_C_same_iprot d tr1 tr2 tg it1 it2 : - item_eq_up_to_C tr1 tr2 tg d it1 it2 → - it1.(iprot) = it2.(iprot). - Proof. - intros H. specialize (H 0). inversion H. done. - Qed. - - Lemma perm_eq_up_to_C_same_init d tr1 tr2 tg off prot lp1 lp2 : - perm_eq_up_to_C tr1 tr2 tg off prot d lp1 lp2 → - initialized lp1 = initialized lp2. - Proof. - intros H. try by inversion H. - Qed. - - Lemma parents_not_disabled_child_not_active tr tg1 tg2 it1 it2 off - (Hwf : wf_tree tr) - (HPP : parents_more_active tr) : - tree_lookup tr tg1 it1 → - tree_lookup tr tg2 it2 → - ParentChildIn tg1 tg2 tr → - perm (item_lookup it1 off) = Disabled → - perm (item_lookup it2 off) = Active → - False. - Proof. - intros Hl1 Hl2 HPC Hp1 Hp2. - specialize (HPP tg1). eapply every_child_ParentChildIn in HPP. - 2: done. 2, 4: eapply Hwf. 2,4: eapply Hl1. 2: eapply Hl2. 2: done. - assert (tg1 = itag it1) as -> by by eapply tree_lookup_correct_tag in Hl1. - assert (tg2 = itag it2) as -> by by eapply tree_lookup_correct_tag in Hl2. - eapply every_node_eqv_universal in HPP. - 2: eapply tree_lookup_to_exists_node, Hl2. - ospecialize (HPP _ _ Hp2). 1: done. congruence. - Qed. - - Lemma disabled_in_practice_not_active tr tg1 tg2 it off - (Hwf : wf_tree tr) - (HPP : parents_more_active tr) - (HNC : no_active_cousins C tr) : - tree_lookup tr tg2 it → - perm (item_lookup it off) = Active → - disabled_in_practice tr tg2 tg1 off → - False. - Proof. - intros Hl1 Hact [it_witness incl H1 H2 H3]. - destruct (decide (perm (item_lookup it_witness off) = Disabled)) as [Hdis|Hnondis]. - + eapply parents_not_disabled_child_not_active. 1: exact Hwf. 1: done. 4: exact Hdis. 4: exact Hact. - 1-2: done. - rewrite /rel_dec in H1. destruct decide; done. - + inversion H3 as [X1 X2 X3|lp X HH1 HH2 X2]; simplify_eq. - { rewrite -X2 in Hnondis. done. } - inversion HH1 as [|tgcs itcs X1 X2 H1' H2' H3' H4 H5 X3 X4]; simplify_eq. - { rewrite -HH2 in Hnondis. done. } - eapply HNC. 1: exact H2'. 1: exact Hl1. 3: exact Hact. 2: right; split; first done. - 2: by rewrite H4. - rewrite /rel_dec in H1|-*. - destruct decide as [HPC1|] in H1; last done. clear H1. - rewrite decide_False; last first. - { intros HPC2. rewrite /rel_dec in H1'. - destruct decide in H1'; try done. - rewrite decide_True // in H1'. - eapply ParentChild_transitive. 1: exact HPC1. done. } - rewrite decide_False //. - intros HPC2. - eapply cousins_have_disjoint_children. 4: exact H1'. 4: exact HPC1. 4: done. - all: eapply Hwf. 1: eapply Hl1. 1: eapply H2. 1: eapply H2'. - Qed. - - Lemma tree_equal_transfer_pseudo_disabled {d tr tr2 tgcld off lp pp} : - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr2 → - no_active_cousins C tr2 → - pseudo_disabled tr2 tgcld off lp pp → - tree_equal d tr tr2 → pseudo_disabled tr tgcld off lp pp. - Proof. - intros Hunq Hwf1 Hwf2 HH (He1&He2&He3). - induction HH as [|tg_cs it_cs lp prot H1 H2 H3 H4 H5]. - 1: econstructor 1. - edestruct He3 as (it_cs1&X&Hit_cs1&HX&Hiteq). - 1: eapply He1, H2. - assert (X = it_cs) as -> by by eapply tree_lookup_unique. - specialize (Hiteq off) as (Hprot&Hiteq). - econstructor 2. 2: exact Hit_cs1. - 1: by rewrite He2. - 1: rewrite Hprot //. - 2: done. - rewrite H4 in Hiteq. - inversion Hiteq as [| | | | | |p1 p2 ini Hd]; simplify_eq. - - congruence. - - exfalso. eapply disabled_in_practice_not_active. - 5: erewrite H4; done. - 4: done. 1: done. 3: eassumption. all: done. - - rewrite -Hprot in H3. f_equal. - destruct d; inversion Hd; done. - Qed. - - Lemma transfer_pseudo_disabled_notimm p1 p2 tr tg off pp : - pseudo_disabled tr tg off p1 pp → - p2 ≠ReservedIM → p1 ≠Disabled → - pseudo_disabled tr tg off p2 pp. - Proof. - intros H Hne1 Hne2. - inversion H as [|X1 X2 X3 X4 X5 X6 X7 X8 X9]. 1: done. econstructor 2. - 1-4: done. done. - Qed. - - Lemma conflicted_transfer_pseudo_disabled c1 c2 tr tg off pp : - pseudo_disabled tr tg off (Reserved c1) pp → - pseudo_disabled tr tg off (Reserved c2) pp. - Proof. - intros HH. eapply transfer_pseudo_disabled_notimm. 1: done. all: done. - Qed. - - Lemma tree_equal_transfer_is_disabled {d tr tr2 tgcld off lp pp} : - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr2 → - no_active_cousins C tr2 → - is_disabled tr2 tgcld off lp pp → - tree_equal d tr tr2 → is_disabled tr tgcld off lp pp. - Proof. - intros Hunq ?? Hdis Heq. - induction Hdis as [|lp prot HH]. - 1: econstructor 1. - econstructor 2. - by eapply tree_equal_transfer_pseudo_disabled. - Qed. - - - Lemma trees_equal_transfer_disabled_in_practice_many {tr2 tgpar tgcld off} : - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr2 → - no_active_cousins C tr2 → - disabled_in_practice tr2 tgcld tgpar off → - ∃ tgpar', - disabled_in_practice tr2 tgcld tgpar' off ∧ - ∀ d tr', tree_equal d tr2 tr' → disabled_in_practice tr' tgcld tgpar' off. - Proof. - intros Hunq1 Hwf1 Hwf2 Hdip. - inversion Hdip as [itw incl Hrel Hlu Hperm]. - rewrite /rel_dec in Hrel. destruct decide as [HPCo|?]; try done. - destruct (trees_equal_decide_disabled_in_practice tr2 tgcld off) as [(tgp&itp&Hlup&Hdisp&HPC&Hothers)|HR]. - 1: done. - { eapply contains_child. 1: done. eapply Hlu. } - 2: { exfalso. eapply HR. 1: exact Hlu. 1: done. done. } - exists tgp. split_and!. - { econstructor. 2: exact Hlup. 2: done. rewrite /rel_dec decide_True //. } - intros d tr1 (Heq1&Heq2&Heq3). - destruct (Heq3 tgp) as (itp'&itp2&Hitp'&Hitp2&Heq). - 1: eapply Hlup. - assert (itp = itp') as <- by by eapply tree_lookup_unique. - specialize (Heq off) as (Hprot&Heq). - inversion Heq as [pp1 X1 HH|ini1 confl1 confl2 HprotX HP1 HP2 HeqX1 HeqX2|ini1 confl1 confl2 HnoProt HeqX1 HeqX2|p1 p2 HP1 HP2 HeqX1 HeqX2|wit_tg lp1 lp2 Hdip1 Hdip2 HiniX HeqX1 HeqX2|ini1 confl1 confl2 wit_tg HF1 HeqX1 HeqX2|p1 p2 ini Hd HeqX1 HeqX2]; simplify_eq. - - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - rewrite -HH -Hprot. - eapply tree_equal_transfer_is_disabled. 1-3: eassumption. 2: eapply tree_equal_sym; done. done. - - rewrite -HeqX1 in Hdisp. - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - inversion Hdisp as [|lp prot HH1 HH2 HH3]; simplify_eq. - rewrite -HeqX2 -Hprot. econstructor 2. - eapply tree_equal_transfer_pseudo_disabled in HH1. 2-4: done. 2: by eapply tree_equal_sym. - by eapply conflicted_transfer_pseudo_disabled. - - rewrite -HeqX1 in Hdisp. - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - inversion Hdisp as [|lp prot HH1 HH2 HH3]; simplify_eq. - rewrite -HeqX2 -Hprot. econstructor 2. - eapply tree_equal_transfer_pseudo_disabled in HH1. 2-4: done. 2: by eapply tree_equal_sym. - by eapply conflicted_transfer_pseudo_disabled. - - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - rewrite -HeqX2. econstructor 2. rewrite -Hprot. done. - - inversion Hdip2 as [itwF incl H1 H2 H3]. - inversion Hdip1 as [itwF' incl' H1' H2' H3']. - assert (incl = incl') as <-. - { rewrite Heq2 H1 in H1'. by simplify_eq. } - rewrite /rel_dec in H1'. destruct decide as [HPCF|] in H1'; last done. - clear H1'. destruct HPCF as [<-|Hne]. - 1: { assert (itwF = itp2) as <- by by eapply tree_lookup_unique. - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. done. } - exfalso. eapply Hothers. 2: exact Hne. 1: done. done. - - rewrite -HeqX1 in Hdisp. - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - inversion Hdisp as [|lp prot HH1 HH2 HH3]; simplify_eq. - rewrite -HeqX2 -Hprot. econstructor 2. - eapply tree_equal_transfer_pseudo_disabled in HH1. 2-4: done. 2: by eapply tree_equal_sym. - by eapply conflicted_transfer_pseudo_disabled. - - rewrite -HeqX1 in Hdisp. - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - inversion Hdisp as [|lp prot HH1 HH2 HH3]; simplify_eq. - 1: destruct d; inversion Hd; done. - rewrite -HeqX2 -Hprot. econstructor 2. - eapply tree_equal_transfer_pseudo_disabled in HH1. 2-4: done. 2: by eapply tree_equal_sym. - eapply transfer_pseudo_disabled_notimm. 1: exact HH1. all: destruct d; inversion Hd; done. - Qed. - - Lemma trees_equal_transfer_disabled_in_practice_twice {d1 d2 tr1 tr2 tr3 tgpar tgcld off} : - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d1 tr1 tr2 → - tree_equal d2 tr2 tr3 → - disabled_in_practice tr2 tgcld tgpar off → - ∃ tgpar', - disabled_in_practice tr1 tgcld tgpar' off ∧ - disabled_in_practice tr2 tgcld tgpar' off ∧ - disabled_in_practice tr3 tgcld tgpar' off. - Proof. - intros H1 Hu1 Hu2 H2%tree_equal_sym H3 Hdip. - odestruct trees_equal_transfer_disabled_in_practice_many as (tg&Htg&Htg2). - 1: exact H1. 1-2: done. 1: exact Hdip. - exists tg. split_and!. - - by eapply Htg2. - - done. - - eapply Htg2. done. - Qed. - - Lemma trees_equal_transfer_frozen_in_practice_many {tr2 tgpar tgcld off} : - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr2 → - no_active_cousins C tr2 → - frozen_in_practice tr2 tgcld tgpar off → - (frozen_in_practice tr2 tgcld tgpar off ∧ - (∀ d tr', tree_equal d tr2 tr' → ∃ p, parent_has_perm p tr' tgcld tgpar off ∧ (p = Frozen ∨ p = Active ∧ d = Forwards))) ∨ - (∃ tgpar', disabled_in_practice tr2 tgcld tgpar' off ∧ - ∀ d tr', tree_equal d tr2 tr' → disabled_in_practice tr' tgcld tgpar' off). - Proof. - intros Hunq1 Hwf1 Hwf2 Hdip. - inversion Hdip as [itw incl Hrel Hlu Hperm Hinit]. - rewrite /rel_dec in Hrel. destruct decide as [HPCo|?]; try done. - destruct (trees_equal_decide_disabled_in_practice tr2 tgcld off) as [(tgp&itp&Hlup&Hdisp&HPC&Hothers)|HR]. - 1: done. - { eapply contains_child. 1: done. eapply Hlu. } - - odestruct trees_equal_transfer_disabled_in_practice_many as (tg&Htg). - 1: exact Hunq1. 1-2: done. 2: { right. exists tg. exact Htg. } - econstructor. 3: done. 2: done. rewrite /rel_dec decide_True //. - - left. split. - 1: done. - intros d tr1 (Heq1&Heq2&Heq3). - destruct (Heq3 tgpar) as (itw'&itw2&Hitw'&Hitw2&Heq). - 1: eapply Hlu. - assert (itw = itw') as <- by by eapply tree_lookup_unique. - assert (∃ p, item_lookup itw2 off = mkPerm PermInit p ∧ (p = Frozen ∨ p = Active ∧ d = Forwards)) as (p&Hitlu&Hp). - { specialize (Heq off) as (HeqL1&HeqL2). - inversion HeqL2 as [pp1|ini1 confl1 confl2 HprotX HP1 HP2 HeqX1 HeqX2|ini1 confl1 confl2 HnoProt HeqX1 HeqX2|lp1 lp2 Hdip1 Hdip2 HeqX1 HeqX2|wit_tg lp1 lp2 Hdip1 Hdip2 HiniX HeqX1 HeqX2|ini1 confl1 confl2 wit_tg HF1 HeqX1 HeqX2|p1 p2 ini Hd HeqX1 HeqX2]; simplify_eq. - + exists Frozen; split; last tauto. destruct item_lookup; simpl in *; simplify_eq. done. - + rewrite -HeqX1 // in Hperm. - + rewrite -HeqX1 // in Hperm. - + rewrite -HeqX1 // in Hinit. - + exists Frozen; split; last tauto. inversion Hdip1 as [itw1' incl1 Hrel1 Hlu1 Hperm1]. - rewrite /rel_dec in Hrel1. destruct decide as [HPC1|?] in Hrel1; last done. - eapply HR in Hperm1. 1: done. 1: done. - eapply ParentChild_transitive. 2: eassumption. done. - + rewrite -HeqX1 // in Hperm. - + rewrite -HeqX1 /= in Hperm Hinit; subst ini. - f_equal. destruct d; inversion Hd; simplify_eq. - eexists; split; first done. by right. } - exists p. split; last done. econstructor. 2: exact Hitw2. - 1: rewrite -Heq2 /rel_dec decide_True //. - all: by rewrite Hitlu. - Qed. - - Lemma item_apply_access_effect_on_initialized - {it it' l b kind rel range} - (Acc : item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C rel range it = Some it') - : initialized (item_lookup it' l) - = if decide (range'_contains range l) - then most_init (initialized (item_lookup it l)) (requires_init rel) - else initialized (item_lookup it l). - Proof. - unfold item_apply_access, permissions_apply_range' in Acc. - rewrite bind_Some in Acc; destruct Acc as [iperm' [iperm'Spec Inj]]. - injection Inj; clear Inj; intros; subst. - pose proof (mem_apply_range'_spec _ _ l _ _ iperm'Spec) as LocalSpec. - case_match. - 2: { rewrite /item_lookup /=. f_equal. f_equal. assumption. } - destruct LocalSpec as [val [valSpec MaybeApply]]. - unfold item_lookup; simpl. - rewrite valSpec; clear valSpec; simpl. - (* Now it's time to actually unfold [maybe_non_children_only] and [apply_access_perm] where - [initialized] *might* be modified. *) - unfold maybe_non_children_only in MaybeApply. rewrite most_init_comm. case_match. - - unfold nonchildren_only in MaybeApply. case_match. - + simpl. case_match. - * injection MaybeApply; intros; subst; reflexivity. - * unfold apply_access_perm in MaybeApply. - destruct (apply_access_perm_inner _ _ _ _); simpl in *; last congruence. - destruct (if most_init _ _ then _ else _); simpl in MaybeApply; last congruence. - injection MaybeApply; clear MaybeApply; intros; subst. - simpl. rewrite most_init_noop. reflexivity. - + unfold apply_access_perm in MaybeApply. - destruct (apply_access_perm_inner _ _ _ _); simpl in *; last congruence. - destruct (if most_init _ _ then _ else _); simpl in MaybeApply; last congruence. - injection MaybeApply; clear MaybeApply; intros; subst. - simpl. rewrite most_init_absorb. reflexivity. - - unfold apply_access_perm in MaybeApply. - destruct (apply_access_perm_inner _ _ _ _); simpl in *; last congruence. - destruct (if most_init _ _ then _ else _); simpl in MaybeApply; last congruence. - injection MaybeApply; clear MaybeApply; intros; subst. - simpl. rewrite most_init_comm. reflexivity. - Qed. - - Lemma perm_eq_up_to_C_preserved_by_access (b:bool) - {d tr1 tr1' tr2 tr2' it1 it1' it2 it2' tg l acc_tg kind range} (Hunq : wf_tree tr2) - (SameProt : iprot it1 = iprot it2) - (SameTg : itag it1 = itag it2) (* note: redundant *) - (SameRel : forall tg tg', rel_dec tr1 tg tg' = rel_dec tr2 tg tg') - (Unq1 : wf_tree tr1) - (Unq2 : wf_tree tr2) - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 → - perm_eq_up_to_C tr1 tr2 tg l (iprot it1) d (item_lookup it1 l) (item_lookup it2 l) -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1 = Some tr1' -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr2 = Some tr2' -> - tree_lookup tr1 tg it1 -> - tree_lookup tr1' tg it1' -> - tree_lookup tr2 tg it2 -> - tree_lookup tr2' tg it2' -> - tree_contains acc_tg tr2 -> - tree_contains acc_tg tr1 -> - item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr1 acc_tg (itag it1)) range it1 = Some it1' -> - item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr2 acc_tg (itag it2)) range it2 = Some it2' -> - perm_eq_up_to_C tr1' tr2' tg l (iprot it1') d (item_lookup it1' l) (item_lookup it2' l). - Proof. - intros Hpma1 Hnac1 Hpma2 Hnac2 HeqTree EqC Acc1 Acc2 Lookup1 Lookup1' Lookup2 Lookup2' Hacctg1 Hacctg2 ItAcc1 ItAcc2. - inversion EqC as [ - p pSpec Equal - |ini confl1 confl2 Prot Confl1 Confl2 itLookup1 itLookup2 - |ini confl1 confl2 NoProt itLookup1 itLookup2 - |p1 p2 Confl1 Confl2 itLookup1 itLookup2 - |????? SameInit - |ini confl1 confl2 witness_tg Hfrz itLookup1 itLookup2 - |p1 p2 ini H1 itLookup1 itLookup2 - ]. - - (* reflexive case *) - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [PermsAcc1 it1'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [PermsAcc2 it2'Spec]]. - injection it2'Spec; intros; subst; clear it2'Spec. - simpl. - pose proof (mem_apply_range'_spec _ _ l _ _ PermsAcc1) as Perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ PermsAcc2) as Perms2'Spec. - destruct (decide _). - + (* within range *) - destruct Perms1'Spec as [p1 [LookupSome1' PermAcc1]]. - destruct Perms2'Spec as [p2 [LookupSome2' PermAcc2]]. - rewrite /item_lookup LookupSome1' LookupSome2' /=. - rewrite /item_lookup in Equal. - rewrite Equal SameRel SameProt SameTg in PermAcc1. - rewrite PermAcc1 in PermAcc2. - injection PermAcc2; intros; subst. constructor. - + (* outside range *) - rewrite /item_lookup in Equal. - rewrite /item_lookup /= Perms1'Spec Perms2'Spec Equal. - constructor. - - (* The permissions are pseudo-conflicted, this restricts the possible accesses. *) - rewrite SameRel SameTg in ItAcc1. - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [perms1'Spec it1'Spec]]. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [perms2'Spec it2'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - injection it2'Spec; intros; subst; clear it2'Spec. - rewrite /item_lookup /=. - pose proof (mem_apply_range'_spec _ _ l _ _ perms1'Spec) as perm1'Spec; clear perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ perms2'Spec) as perm2'Spec; clear perms2'Spec. - (* Now we do the case analysis of the access that occured *) - (* First off, if we're out of range then we can take the exact same witness. *) - destruct (decide (range'_contains range l)). - 2: { - rewrite perm1'Spec. - rewrite perm2'Spec. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 -itLookup2. - econstructor. - + assumption. - + inversion Confl1; subst. - * constructor. - * eapply access_preserves_pseudo_conflicted_activable; eassumption. - + inversion Confl2; subst. - * constructor. - * eapply access_preserves_pseudo_conflicted_activable; eassumption. - } - (* Now we're within range *) - destruct perm1'Spec as [perm1' [perm1'Lookup perm1'Spec]]. - destruct perm2'Spec as [perm2' [perm2'Lookup perm2'Spec]]. - rewrite perm1'Lookup perm2'Lookup; clear perm1'Lookup perm2'Lookup. - simpl. - rewrite bool_decide_eq_true_2 in perm1'Spec; [|assumption]. - rewrite bool_decide_eq_true_2 in perm2'Spec; [|rewrite -SameProt; assumption]. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 in perm1'Spec; clear itLookup1. - rewrite -itLookup2 in perm2'Spec; clear itLookup2. - destruct (maybe_non_children_only_effect_or_nop b (apply_access_perm kind) (rel_dec tr2 acc_tg (itag it2))) as [Heff|Heff]. - all: rewrite !Heff /= in perm1'Spec,perm2'Spec. - 2: { simplify_eq. econstructor; first done. all: by eapply access_preserves_pseudo_conflicted. } - (* Next we need to unwrap the apply_access_perm to get to apply_access_perm_inner *) - rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [perm1 [perm1Spec perm1'Spec]]. - rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [tmp1 [tmp1Spec perm1'Spec]]. - injection perm1'Spec; simpl; intros; subst; clear perm1'Spec. - rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [perm2 [perm2Spec perm2'Spec]]. - rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [tmp2 [tmp2Spec perm2'Spec]]. - injection perm2'Spec; simpl; intros; subst; clear perm2'Spec. - simpl in *. - (* We can finally start the big case analysis at the level of the state machine *) - destruct (most_init _), perm1, perm2; try congruence. - all: injection tmp1Spec; intros; subst; clear tmp1Spec. - all: injection tmp2Spec; intros; subst; clear tmp2Spec. - all: destruct kind, (rel_dec _ _ _) eqn:relation, confl1; simpl in *; try discriminate. - all: destruct confl2; simpl in *; try discriminate. - all: try (injection perm1Spec; intros; subst); clear perm1Spec. - all: try (injection perm2Spec; intros; subst); clear perm2Spec. - all: try constructor; auto. - all: try constructor. - (* Now they are all ResActivable and we need to show that the cousin is still a witness. - See the above lemma for exactly that. *) - all: eapply access_preserves_pseudo_conflicted_activable; eassumption. - - (* The permissions are formerly pseudo-conflicted, but the difference should no longer matter now. *) - rewrite SameRel SameTg in ItAcc1. - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [perms1'Spec it1'Spec]]. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [perms2'Spec it2'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - injection it2'Spec; intros; subst; clear it2'Spec. - rewrite /item_lookup /=. - pose proof (mem_apply_range'_spec _ _ l _ _ perms1'Spec) as perm1'Spec; clear perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ perms2'Spec) as perm2'Spec; clear perms2'Spec. - (* Now we do the case analysis of the access that occured *) - (* First off, if we're out of range then we can take the exact same witness. *) - destruct (decide (range'_contains range l)). - 2: { - rewrite perm1'Spec. - rewrite perm2'Spec. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 -itLookup2. - econstructor 3. - assumption. - } - (* Now we're within range *) - destruct perm1'Spec as [perm1' [perm1'Lookup perm1'Spec]]. - destruct perm2'Spec as [perm2' [perm2'Lookup perm2'Spec]]. - rewrite perm1'Lookup perm2'Lookup; clear perm1'Lookup perm2'Lookup. - simpl. - rewrite bool_decide_eq_false_2 in perm1'Spec; [|assumption]. - rewrite bool_decide_eq_false_2 in perm2'Spec; [|rewrite -SameProt; assumption]. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 in perm1'Spec; clear itLookup1. - rewrite -itLookup2 in perm2'Spec; clear itLookup2. - destruct (maybe_non_children_only_effect_or_nop b (apply_access_perm kind) (rel_dec tr2 acc_tg (itag it2))) as [Heff|Heff]. - all: rewrite !Heff /= in perm1'Spec,perm2'Spec. - 2: { simplify_eq. econstructor; first done. all: by eapply access_preserves_pseudo_conflicted. } - (* Next we need to unwrap the apply_access_perm to get to apply_access_perm_inner *) - rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [perm1 [perm1Spec perm1'Spec]]. - rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [tmp1 [tmp1Spec perm1'Spec]]. - injection perm1'Spec; simpl; intros; subst; clear perm1'Spec. - rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [perm2 [perm2Spec perm2'Spec]]. - rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [tmp2 [tmp2Spec perm2'Spec]]. - injection perm2'Spec; simpl; intros; subst; clear perm2'Spec. - simpl in *. - (* We can finally start the big case analysis at the level of the state machine *) - edestruct (most_init ini _), perm1, perm2; try congruence. - all: injection tmp1Spec; intros; subst; clear tmp1Spec. - all: injection tmp2Spec; intros; subst; clear tmp2Spec. - all: destruct kind, (rel_dec _ _ _) eqn:relation, confl1; simpl in *; try discriminate. - all: destruct confl2; simpl in *; try discriminate. - all: try (injection perm1Spec; intros; subst); clear perm1Spec. - all: try (injection perm2Spec; intros; subst); clear perm2Spec. - all: try by econstructor 1. - all: try by econstructor 3. - (* pseudo-disabled *) - - rewrite SameRel SameTg in ItAcc1. - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [perms1'Spec it1'Spec]]. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [perms2'Spec it2'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - injection it2'Spec; intros; subst; clear it2'Spec. - rewrite /item_lookup /=. - pose proof (mem_apply_range'_spec _ _ l _ _ perms1'Spec) as perm1'Spec; clear perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ perms2'Spec) as perm2'Spec; clear perms2'Spec. - (* Now we do the case analysis of the access that occured *) - (* First off, if we're out of range then we can take the exact same witness. *) - destruct (decide (range'_contains range l)). - 2: { - rewrite perm1'Spec. - rewrite perm2'Spec. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 -itLookup2. - econstructor 4. - all: eapply access_preserves_pseudo_disabled; first done. - all: done. - } - (* Now we're within range *) - destruct perm1'Spec as [perm1' [perm1'Lookup perm1'Spec]]. - destruct perm2'Spec as [perm2' [perm2'Lookup perm2'Spec]]. - rewrite perm1'Lookup perm2'Lookup; clear perm1'Lookup perm2'Lookup. - simpl. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 in perm1'Spec; clear itLookup1. - rewrite -itLookup2 in perm2'Spec; clear itLookup2. - edestruct (maybe_non_children_only_effect_or_nop b (apply_access_perm kind) (rel_dec tr2 acc_tg (itag it2))) as [Heff|Heff]. - all: rewrite !Heff /= in perm1'Spec,perm2'Spec. all: clear Heff. - 2: { injection perm1'Spec as <-. injection perm2'Spec as <-. - econstructor 4. - all: eapply access_preserves_pseudo_disabled; first done. - all: done. } - (* Next we need to unwrap the apply_access_perm to get to apply_access_perm_inner *) - rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [perm1 [perm1Spec perm1'Spec]]. - rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [perm2 [perm2Spec perm2'Spec]]. - assert (¬ ParentChildIn (itag it2) acc_tg tr2) as HnPC. - { intros HnPC. clear perm1'Spec perm1Spec. - inversion Confl2 as [|tg_cs it_cs X1 X2 H1 H2 H3 H4 H5]; simplify_eq. - 1: { rewrite /apply_access_perm_inner /= in perm2Spec. - rewrite /rel_dec decide_True // in perm2Spec. by destruct kind. } - destruct (apply_access_spec_per_node (proj1 H2) (proj2 H2) Acc2) - as (cous' & cous'_spec & cous'_ex & cous'_det). - symmetry in cous'_spec. - rewrite bind_Some in cous'_spec. - destruct cous'_spec as (perms' & perms'_spec & cous'_build). - injection cous'_build; intros; subst; clear cous'_build. - pose proof (mem_apply_range'_spec _ _ l _ _ perms'_spec) as effect_at_l. - rewrite decide_True // in effect_at_l. - destruct effect_at_l as (perm' & perm'_lookup & perm'_spec). - rewrite /item_lookup in H4. rewrite H4 in perm'_spec. - rewrite bool_decide_true in perm'_spec. 2: done. - assert (tg_cs = itag it_cs) as -> by (symmetry; by eapply tree_lookup_correct_tag). - assert (tg = itag it2) as -> by (symmetry; by eapply tree_lookup_correct_tag). - rewrite /rel_dec decide_False in perm'_spec. - 2: { intros Hx. eapply cousins_have_disjoint_children. 4: eassumption. 4-5: done. - all: eapply Hunq. 1: done. 1: eapply Lookup2. 1: eapply H2. } - rewrite decide_False in perm'_spec. - 2: { intros Hx. rewrite /rel_dec in H1. - destruct decide as [|HH1] in H1; first done. - destruct decide as [|HH2] in H1; first done. - eapply HH2. eapply ParentChild_transitive. 2: exact Hx. 1: done. } - rewrite maybe_non_children_only_no_effect in perm'_spec. 2: done. - destruct kind in perm'_spec; cbv in perm'_spec; done. } - rewrite /rel_dec decide_False // /= in perm2'Spec. injection perm2'Spec as <-. - rewrite /rel_dec decide_False // /= in perm1'Spec. injection perm1'Spec as <-. - rewrite /rel_dec decide_False // /= in perm2Spec. - rewrite /rel_dec decide_False // /= in perm1Spec. - econstructor 4; eapply access_preserves_pseudo_disabled. 2,4: done. - + inversion Confl1 as [|X1 X2 X3 X4 X5 X6 X7 X8 H]; simplify_eq. - 1: destruct kind, bool_decide in perm1Spec; cbv in perm1Spec; injection perm1Spec as <-; econstructor 1. - econstructor 2. 1-4: done. - intros ->. - destruct (bool_decide (protector_is_active (iprot it1) C)), kind, p1 as [[]| | | |]; try discriminate perm1Spec. - all: done. - + inversion Confl2 as [|X1 X2 X3 X4 X5 X6 X7 X8 H]; simplify_eq. - 1: destruct kind, bool_decide in perm1Spec; cbv in perm2Spec; injection perm2Spec as <-; econstructor 1. - econstructor 2. 1-4: done. - intros ->. - destruct (bool_decide (protector_is_active (iprot it2) C)), kind, p2 as [[]| | | |]; try discriminate perm2Spec. - all: done. - - econstructor. - + eapply disabled_in_practice_tree_apply_access_irreversible; last eassumption. 2-3: done. - eassumption. - + eapply disabled_in_practice_tree_apply_access_irreversible; last eassumption. 2-3: done. - eassumption. - + rewrite (item_apply_access_effect_on_initialized ItAcc1). - rewrite (item_apply_access_effect_on_initialized ItAcc2). - rewrite SameInit. - case_match; last reflexivity. - f_equal. f_equal. rewrite SameTg. apply SameRel. - - (* Proof idea: - each item is Reserved. Therefore it can: - - get a child read: nothing happens - - get a child write: it's UB, since the parent is frozen - - get a foreign read: the conflictedness might change but that's OK, this case is precisely for that - - get a foreign write: it's either UB or we remain, depending on interior mutability. - + however, since such a write must disable our parent, it should not matter that IM is the same here. - But reasoning about this is complicated (because of maybe_nonchildren_only) so let's just not. *) - (* We're frozen in practice *) - pose trd := (match d with Forwards => tr1 | Backwards => tr2 end). fold trd in Hfrz. - pose trd' := (match d with Forwards => tr2 | Backwards => tr1 end). - eapply trees_equal_transfer_frozen_in_practice_many in Hfrz as [(Hfrz&Hfrzo)|(tdis&Htdis&Htdiso)]. - 3-5: by destruct d. - 2: { econstructor. - + eapply disabled_in_practice_tree_apply_access_irreversible; last eassumption. 2-3: done. - destruct d; try done. eapply Htdiso, tree_equal_sym, HeqTree. - + eapply disabled_in_practice_tree_apply_access_irreversible; last eassumption. 2-3: done. - destruct d; try done. eapply Htdiso, HeqTree. - + rewrite (item_apply_access_effect_on_initialized ItAcc1). - rewrite (item_apply_access_effect_on_initialized ItAcc2). - rewrite -itLookup1 -itLookup2 /=. - case_match; last reflexivity. - f_equal. f_equal. rewrite SameTg. apply SameRel. } - destruct (Hfrzo Forwards trd') as (p'&Hfrzalmost&Hfrz'). - 1: destruct d; first done. 1: eapply tree_equal_sym in HeqTree; exact HeqTree. - rewrite SameRel SameTg in ItAcc1. - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [perms1'Spec it1'Spec]]. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [perms2'Spec it2'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - injection it2'Spec; intros; subst; clear it2'Spec. - rewrite /item_lookup /=. - pose proof (mem_apply_range'_spec _ _ l _ _ perms1'Spec) as perm1'Spec; clear perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ perms2'Spec) as perm2'Spec; clear perms2'Spec. - (* Now we do the case analysis of the access that occured *) - (* First off, if we're out of range then we can take the exact same witness. *) - destruct (decide (range'_contains range l)) eqn:Hrangedec. - 2: { - rewrite perm1'Spec. - rewrite perm2'Spec. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 -itLookup2. - econstructor 6; destruct d. - - eapply frozen_in_practice_tree_apply_access_irreversible in Hfrz. 4: exact Acc1. 2-3: done. - destruct Hfrz as [(Hf&HX)|(Hf&HX)]; first done. - rewrite /becomes_disabled Hrangedec in HX. done. - - eapply frozen_in_practice_tree_apply_access_irreversible in Hfrz. 4: exact Acc2. 2-3: done. - destruct Hfrz as [(Hf&HX)|(Hf&HX)]; first done. - rewrite /becomes_disabled Hrangedec in HX. done. - } - (* Now we're within range *) - destruct perm1'Spec as [perm1' [perm1'Lookup perm1'Spec]]. - destruct perm2'Spec as [perm2' [perm2'Lookup perm2'Spec]]. - rewrite perm1'Lookup perm2'Lookup; clear perm1'Lookup perm2'Lookup. - simpl. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 in perm1'Spec; clear itLookup1. - rewrite -itLookup2 in perm2'Spec; clear itLookup2. - assert (∃ p, parent_has_perm p (match d with Backwards => tr1 | _ => tr2 end) tg witness_tg l ∧ (p = Frozen ∨ p = Active)) as (pt&Htrans&Hptrans). - { destruct Hfrz' as [ -> |(->&_)]; eexists; (split; first done). all: tauto. } - eapply @frozen_in_practice_tree_apply_access_irreversible with (tr' := match d with Forwards => _ | _ => _ end) in Hfrz; last (destruct d; [exact Acc1|exact Acc2]). 2-3: by destruct d. - destruct Hfrz as [(H1&HX)|(H1&HX)]. - all: edestruct (maybe_non_children_only_effect_or_nop b (apply_access_perm kind) (rel_dec tr2 acc_tg (itag it2))) as [Heff|Heff]. - all: rewrite !Heff /= in perm1'Spec,perm2'Spec; clear Heff. - 2: { simplify_eq. econstructor 6; eassumption. } - 3: { eapply @parent_has_perm_similarly_disabled with (tr' := match d with Forwards => tr2' | _ => tr1' end) in Htrans. - 4: by destruct d. 4: by destruct d. 3: destruct d; done. - 3: { rewrite /becomes_disabled in HX|-*. destruct d. - 1: rewrite -SameRel //. rewrite SameRel //. } - 2: destruct Hptrans; by simplify_eq. - econstructor 5. 3: by simplify_eq. - all: eapply parent_has_disabled_perm_is_pseudo_disabled; by destruct d. } - (* Next we need to unwrap the apply_access_perm to get to apply_access_perm_inner *) - all: rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [perm1 [perm1Spec perm1'Spec]]. - all: rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [tmp1 [tmp1Spec perm1'Spec]]. - all: injection perm1'Spec; simpl; intros; subst; clear perm1'Spec. - all: rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [perm2 [perm2Spec perm2'Spec]]. - all: rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [tmp2 [tmp2Spec perm2'Spec]]. - all: injection perm2'Spec; simpl; intros; subst; clear perm2'Spec. - 2: { eapply @parent_has_perm_similarly_disabled with (tr' := match d with Forwards => tr2' | _ => tr1' end) in Htrans. - 4: by destruct d. 4: by destruct d. 3: destruct d; done. - 3: { rewrite /becomes_disabled in HX|-*. destruct d. - 1: rewrite -SameRel //. rewrite SameRel //. } - 2: destruct Hptrans; by simplify_eq. - econstructor 5. 3: by simplify_eq. - all: eapply parent_has_disabled_perm_is_pseudo_disabled; by destruct d. } - simpl in *. rewrite -SameProt in tmp2Spec,perm2Spec. - (* We can finally start the big case analysis at the level of the state machine *) - edestruct (most_init ini _), perm1, perm2, (bool_decide (protector_is_active (iprot it1) C)); try congruence. - all: injection tmp1Spec; intros; subst; clear tmp1Spec. - all: injection tmp2Spec; intros; subst; clear tmp2Spec. - all: destruct kind, (rel_dec _ _ _) eqn:relation, confl1; simpl in *; try discriminate. - all: destruct confl2; simpl in *; try discriminate. - all: try (injection perm1Spec; intros; subst); clear perm1Spec. - all: try (injection perm2Spec; intros; subst); clear perm2Spec. - all: try by econstructor 1. - all: try by econstructor 6. - - (* asymmetric *) - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [PermsAcc1 it1'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [PermsAcc2 it2'Spec]]. - injection it2'Spec; intros; subst; clear it2'Spec. - simpl. - pose proof (mem_apply_range'_spec _ _ l _ _ PermsAcc1) as Perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ PermsAcc2) as Perms2'Spec. - rewrite /item_lookup /= in itLookup1,itLookup2. - destruct (decide _); last first. - { rewrite /item_lookup /= Perms1'Spec Perms2'Spec -itLookup1 -itLookup2. - econstructor 7. done. } - destruct Perms1'Spec as [p1' [LookupSome1' PermAcc1]]. - destruct Perms2'Spec as [p2' [LookupSome2' PermAcc2]]. - rewrite -itLookup1 in PermAcc1. - rewrite -itLookup2 in PermAcc2. - rewrite -SameProt -SameTg -SameRel in PermAcc2. - edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]; erewrite Heq in PermAcc1, PermAcc2; clear Heq. - 2: { injection PermAcc1 as <-; injection PermAcc2 as <-. - rewrite /item_lookup /= LookupSome1' LookupSome2' /=. by econstructor 7. } - destruct ini, d, kind, (rel_dec tr1 acc_tg (itag it1)); simpl in *. - all: inversion H1 as [P|P]; subst P p1 p2; [ - rewrite bool_decide_eq_false_2 // in PermAcc1,PermAcc2 - | rewrite bool_decide_eq_true_2 // in PermAcc1,PermAcc2]. - all: rewrite /apply_access_perm /apply_access_perm_inner /= in PermAcc1,PermAcc2; - try discriminate PermAcc1; try discriminate PermAcc2; - injection PermAcc1 as <-; injection PermAcc2 as <-. - all: rewrite /item_lookup /= LookupSome1' LookupSome2' /=. - all: try econstructor 1. - all: econstructor 7; simpl; econstructor; done. - Qed. - - Lemma item_eq_up_to_C_preserved_by_access (b : bool) - {d tr1 tr1' tr2 tr2' it1 it1' it2 it2' tg acc_tg kind range} (Hunq1 : wf_tree tr1) (Hunq2 : wf_tree tr2) - (SameTg : itag it1 = itag it2) - (SameRel : forall tg tg', rel_dec tr1 tg tg' = rel_dec tr2 tg tg') - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 → - item_eq_up_to_C tr1 tr2 tg d it1 it2 -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1 = Some tr1' -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr2 = Some tr2' -> - tree_lookup tr1 tg it1 -> - tree_lookup tr1' tg it1' -> - tree_lookup tr2 tg it2 -> - tree_lookup tr2' tg it2' -> - tree_contains acc_tg tr1 -> - tree_contains acc_tg tr2 -> - item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr1 acc_tg (itag it1)) range it1 = Some it1' -> - item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr2 acc_tg (itag it2)) range it2 = Some it2' -> - item_eq_up_to_C tr1' tr2' tg d it1' it2'. - Proof. - intros ????? EqC Acc1 Acc2 Lookup1 Lookup1' Lookup2 Lookup2' AccTg1 AccTg2 ItAcc1 ItAcc2. - econstructor. - - rewrite <- (proj1 (proj2 (item_apply_access_preserves_metadata _ _ ItAcc1))). - rewrite <- (proj1 (proj2 (item_apply_access_preserves_metadata _ _ ItAcc2))). - apply EqC. assumption. - - eapply perm_eq_up_to_C_preserved_by_access. - + done. - + apply EqC. assumption. - + apply SameTg. - + apply SameRel. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + apply EqC. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - Qed. - - Lemma tree_equal_preserved_by_access_maybe_nonchildren_only (b : bool) - {d tr1 tr2 tr1' tr2' kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 -> - tree_contains acc_tg tr1 -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1 = Some tr1' -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr2 = Some tr2' -> - tree_equal d tr1' tr2'. - Proof. - intros ???? Heq. pose proof Heq as [SameTg [SameRel EqC]]. intros ExAcc Acc1 Acc2. - split; [|split]. - - intros tg. - rewrite <- (access_preserves_tags Acc1). - rewrite <- (access_preserves_tags Acc2). - apply SameTg. - - intros tg tg'. - rewrite <- (access_same_rel_dec Acc1). - rewrite <- (access_same_rel_dec Acc2). - apply SameRel. - - intros tg Ex1'. - pose proof (proj2 (access_preserves_tags Acc1) Ex1') as Ex1. - pose proof (proj1 (SameTg _) Ex1) as Ex2. - pose proof (proj1 (access_preserves_tags Acc2) Ex2) as Ex2'. - destruct (EqC tg Ex1) as [it1 [it2 [Lookup1 [Lookup2 EqC12]]]]. - destruct (apply_access_spec_per_node Ex1 (proj2 Lookup1) Acc1) as [it1' [it1'Spec [_ Lookup1']]]. - destruct (apply_access_spec_per_node Ex2 (proj2 Lookup2) Acc2) as [it2' [it2'Spec [_ Lookup2']]]. - exists it1'. exists it2'. - split; [|split]. - + split; assumption. - + split; assumption. - + eapply item_eq_up_to_C_preserved_by_access. - * exact GloballyUnique1. - * exact GloballyUnique2. - * erewrite tree_lookup_correct_tag; [|exact Lookup1]. - erewrite tree_lookup_correct_tag; [|exact Lookup2]. - reflexivity. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * split; eassumption. - * eassumption. - * split; eassumption. - * eassumption. - * by eapply SameTg. - * symmetry; assumption. - * symmetry; assumption. - Qed. - - Lemma tree_equal_preserved_by_memory_access - {d tr1 tr2 tr1' tr2' kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 -> - tree_contains acc_tg tr1 -> - memory_access kind C acc_tg range tr1 = Some tr1' -> - memory_access kind C acc_tg range tr2 = Some tr2' -> - tree_equal d tr1' tr2'. - Proof. - by eapply (tree_equal_preserved_by_access_maybe_nonchildren_only false). - Qed. - - Lemma tree_equal_preserved_by_memory_access_nonchildren_only - {d tr1 tr2 tr1' tr2' kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 -> - tree_contains acc_tg tr1 -> - memory_access_nonchildren_only kind C acc_tg range tr1 = Some tr1' -> - memory_access_nonchildren_only kind C acc_tg range tr2 = Some tr2' -> - tree_equal d tr1' tr2'. - Proof. - by eapply (tree_equal_preserved_by_access_maybe_nonchildren_only true). - Qed. - - Lemma tree_equal_memory_deallocate - {d tr1 tr2 tr1' tr2' acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 -> - tree_contains acc_tg tr1 -> - memory_deallocate C acc_tg range tr1 = Some tr1' -> - memory_deallocate C acc_tg range tr2 = Some tr2' -> - tree_equal d tr1' tr2'. - Proof. - intros ???? Heq Hcontains (pw1&Hacc1&<-%join_map_id_is_Some_identical)%bind_Some - (pw2&Hacc2&<-%join_map_id_is_Some_identical)%bind_Some. - by eapply (@tree_equal_preserved_by_memory_access d tr1 tr2). - Qed. - - Lemma is_Some_if {A} (P : bool) (s:A) : is_Some (if P then Some s else None) → P. - Proof. - destruct P; first done. - intros (x&[=]). - Qed. - - Lemma is_Some_if_neg {A} (P : bool) (s:A) : is_Some (if P then None else Some s) → P = false. - Proof. - destruct P; last done. - intros (x&[=]). - Qed. - - Lemma tree_equal_allows_more_deallocation - {tr1 tr2 acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (PMI : parents_more_init tr2) : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal Forwards tr1 tr2 -> - tree_unique acc_tg tr1 -> - is_Some (memory_deallocate C acc_tg range tr1) -> - is_Some (memory_deallocate C acc_tg range tr2). - Proof. - intros ???? Heq Hunq (tr1'&(pw1&Hpw1&Htrr%mk_is_Some)%bind_Some). - pose proof Hpw1 as HH. - eapply mk_is_Some, tree_equal_allows_more_access in HH as (pw2&Hpw2). 2-8: done. - opose proof (tree_equal_preserved_by_memory_access _ _ _ _ _ _ _ _ Hpw1 Hpw2) as Heqpw. - 1-3: done. 1-4: done. 1: by eapply unique_exists. - rewrite /memory_deallocate Hpw2 /option_bind //. - eapply join_success_condition, every_node_map, every_node_eqv_universal. - intros itm2 Hitm2%exists_node_to_tree_lookup. - 2: { intros ttg Hcont. - eapply access_preserves_tags, GloballyUnique2 in Hcont. - 2: apply Hpw2. setoid_rewrite <- tree_apply_access_preserve_unique; last apply Hpw2. - done. } - assert (tree_contains (itag itm2) pw2) as Hcont by apply Hitm2. - destruct Heqpw as (Hsame&_&Hacc). setoid_rewrite <- Hsame in Hcont. - apply Hacc in Hcont as (itm1&itm2'&Hlu1&Hlu2&Hiteq). - assert (itm2' = itm2) as ->. - 1: eapply tree_determined_unify. 1,3: eapply Hitm2. 1: eapply Hlu2. - assert (itag itm1 = itag itm2) as Htageq. - 1: eapply tree_lookup_correct_tag, Hlu1. - eapply join_success_condition in Htrr. - setoid_rewrite every_node_map in Htrr. - eapply every_node_eqv_universal in Htrr. - 2: { eapply tree_lookup_to_exists_node. rewrite -Htageq in Hlu1. done. } - simpl in Htrr. eapply is_Some_if_neg in Htrr. - destruct (Hiteq 0) as (Hloceq&_). simpl. - rewrite -!Hloceq Htrr. done. - Qed. - - Lemma trees_equal_insert d tr1 tr2 ttr1 ttr2 blk : - trees_equal d tr1 tr2 → - tree_equal d ttr1 ttr2 → - trees_equal d (<[blk := ttr1]> tr1) (<[blk := ttr2]> tr2). - Proof. - intros Htr Httr blk'. - destruct (decide (blk = blk')) as [Heq|Hne]. - - rewrite -!Heq !lookup_insert. by econstructor. - - rewrite !lookup_insert_ne //. - Qed. - - Lemma apply_within_trees_equal d fn blk tr1 tr1' tr2 : - (∀ ttr1 ttr1' ttr2, fn ttr1 = Some ttr1' → tree_equal d ttr1 ttr2 → - tr1 !! blk = Some ttr1 → tr1' !! blk = Some ttr1' → tr2 !! blk = Some ttr2 → - ∃ ttr2', fn ttr2 = Some ttr2' ∧ tree_equal d ttr1' ttr2') → - apply_within_trees fn blk tr1 = Some tr1' → - trees_equal d tr1 tr2 → - ∃ tr2', apply_within_trees fn blk tr2 = Some tr2' ∧ - trees_equal d tr1' tr2'. - Proof. - intros Hfn Happly Heq. - rewrite /apply_within_trees in Happly|-*. - specialize (Heq blk) as Heqblk. - inversion Heqblk as [ttr1 ttr2 Hteq Htr1 Htr2|HN1 HN2]; last rewrite -HN1 // in Happly. - rewrite -Htr1 -?Htr2 /= in Happly|-*. - destruct (fn ttr1) as [ttr1'|] eqn:Hfnttr1; last done. - rewrite /= in Happly. injection Happly as <-. - destruct (Hfn ttr1 ttr1' ttr2) as (ttr2' & Hfnttr2 & Heq'); try done. - 1: by rewrite lookup_insert. - rewrite Hfnttr2 /=. eexists; split; first done. - by apply trees_equal_insert. - Qed. - - Lemma trees_equal_delete d tr1 tr2 blk : - trees_equal d tr1 tr2 → - trees_equal d (delete blk tr1) (delete blk tr2). - Proof. - intros Htr blk'. - destruct (decide (blk = blk')) as [Heq|Hne]. - - rewrite -!Heq !lookup_delete. by econstructor. - - rewrite !lookup_delete_ne //. - Qed. - - Lemma trees_equal_init_trees d ts tt tg bl off sz : - trees_equal d ts tt → - trees_equal d (extend_trees tg bl off sz ts) (extend_trees tg bl off sz tt). - Proof. - intros Htrs. apply trees_equal_insert; first done. - eapply tree_equal_reflexive. - eapply wf_tree_tree_item_determined. - eapply wf_init_tree. - Qed. - - Lemma tree_all_protected_initialized_elem_of cid tr tg lst - (AllUnique : forall tg, tree_contains tg tr -> tree_unique tg tr) : - (tg, lst) ∈ tree_get_all_protected_tags_initialized_locs cid tr ↔ - ∃ it, tree_lookup tr tg it ∧ protector_is_for_call cid it.(iprot) ∧ - ∀ z v, lst !! z = Some v ↔ initialized (item_lookup it z) = PermInit ∧ (v = AccessWrite ↔ perm (item_lookup it z) = Active). - Proof. - setoid_rewrite tree_all_protected_initialized_exists_node. - split. - - intros (it&Hexit%exists_node_to_tree_lookup&Htg&Hprot&Hinit)%exists_node_eqv_existential. 2: done. - rewrite Htg in Hexit. by eexists. - - intros (it&Hit&Hprops). assert (itag it = tg) as <- by by eapply tree_lookup_correct_tag. - eapply exists_node_eqv_existential. eexists; split; last done. - by eapply tree_lookup_to_exists_node. - Qed. - - Lemma parents_not_disabled_child_not_prot_init tr tg1 tg2 it1 it2 off - (Hwf : wf_tree tr) - (HH : protected_parents_not_disabled C tr) : - tree_lookup tr tg1 it1 → - tree_lookup tr tg2 it2 → - ParentChildIn tg1 tg2 tr → - perm (item_lookup it1 off) = Disabled → - initialized (item_lookup it2 off) = PermInit → - protector_is_active (iprot it2) C → - False. - Proof. - intros Hl1 Hl2 HPC Hp1 Hp2 Hp3. - specialize (HH tg1). eapply every_child_ParentChildIn in HH. - 2: done. 2, 4: eapply Hwf. 2,4: eapply Hl1. 2: eapply Hl2. 2: done. - assert (tg1 = itag it1) as -> by by eapply tree_lookup_correct_tag in Hl1. - assert (tg2 = itag it2) as -> by by eapply tree_lookup_correct_tag in Hl2. - eapply every_node_eqv_universal in HH. - 2: eapply tree_lookup_to_exists_node, Hl2. - ospecialize (HH _ _ Hp2 Hp3). 1: done. congruence. - Qed. - - Lemma disabled_in_practice_not_prot_init tr tg1 tg2 it off - (Hwf : wf_tree tr) - (HNC : no_active_cousins C tr) - (HH : protected_parents_not_disabled C tr) : - tree_lookup tr tg2 it → - initialized (item_lookup it off) = PermInit → - protector_is_active (iprot it) C → - disabled_in_practice tr tg2 tg1 off → - False. - Proof. - intros Hl1 Hini Hperm [it_witness incl H1 H2 H3]. - destruct (decide (perm (item_lookup it_witness off) = Disabled)) as [Hdis|Hnondis]. - + eapply parents_not_disabled_child_not_prot_init. 1: exact Hwf. 1: done. 4: exact Hdis. 4: exact Hini. 4: exact Hperm. - 1-2: done. - rewrite /rel_dec in H1. destruct decide; done. - + inversion H3 as [X1 X2 X3|lp X HH1 HH2 X2]; simplify_eq. - { rewrite -X2 in Hnondis. done. } - inversion HH1 as [|tgcs itcs X1 X2 H1' H2' H3' H4 H5 X3 X4]; simplify_eq. - { rewrite -HH2 in Hnondis. done. } - eapply HNC. 1: exact Hl1. 1: exact H2'. 3: by erewrite H4. - 2: right; split. 2: done. 2: done. - rewrite rel_dec_flip2 /=. - rewrite /rel_dec in H1|-*. - destruct decide as [HPC1|] in H1; last done. clear H1. - rewrite decide_False; last first. - { intros HPC2. rewrite /rel_dec in H1'. - destruct decide in H1'; try done. - rewrite decide_True // in H1'. - eapply ParentChild_transitive. 1: exact HPC1. done. } - rewrite decide_False //. - intros HPC2. - eapply cousins_have_disjoint_children. 4: exact H1'. 4: exact HPC1. 4: done. - all: eapply Hwf. 1: eapply Hl1. 1: eapply H2. 1: eapply H2'. - Qed. - - Lemma item_wf_item_lookup_active it ev1 ev2 off : - item_wf it ev1 ev2 → - perm (item_lookup it off) = Active → - initialized (item_lookup it off) = PermInit. - Proof. - intros Hwf. - rewrite /item_lookup. destruct (iperm it !! off) as [p|] eqn:Heq. - - rewrite /=. eapply map_Forall_lookup_1 in Heq. 2: by eapply item_perms_valid. apply Heq. - - simpl. intros HH. exfalso; by eapply item_default_perm_valid. - Qed. - - - Lemma perm_eq_up_to_C_same_protected_active d tr1 tr2 tg off prot it1 it2 ev1 ev2 - (Hwf1 : wf_tree tr1) - (Hwf2 : wf_tree tr2) - (ProtParentsNonDis1 : protected_parents_not_disabled C tr1) - (ProtParentsNonDis2 : protected_parents_not_disabled C tr2) - (HCS1 : no_active_cousins C tr1) - (HCS2 : no_active_cousins C tr2) - (Hiwf1 : item_wf it1 ev1 ev2) - (Hiwf2 : item_wf it2 ev1 ev2) : - tree_lookup tr1 tg it1 → - tree_lookup tr2 tg it2 → - prot = iprot it1 → prot = iprot it2 → - protector_is_active prot C → - perm_eq_up_to_C tr1 tr2 tg off prot d (item_lookup it1 off) (item_lookup it2 off) → - perm (item_lookup it1 off) = Active ↔ perm (item_lookup it2 off) = Active. - Proof. - intros Hl1 Hl2 Hiprot1 Hiprot2 Hprot H. inversion H as [| | |p1 p2 HX1 HX2 HX3 HX4|X1 X2 X3 X4 X5 X6 X7| |p1 p2 ini Hr]; try done; simplify_eq. - - simpl; split; intros Hact; exfalso. - + rewrite /item_lookup in HX3. - destruct lookup eqn:Heq in HX3. - 2: { simpl in HX3. injection HX3 as ->. - eapply item_default_perm_valid in Hact; done. } - rewrite /= in HX3. subst. - eapply item_perms_valid in Heq. 2: done. - simpl in Heq. by ospecialize (Heq _). - + rewrite /item_lookup in HX4. - destruct lookup eqn:Heq in HX4. - 2: { simpl in HX3. injection HX4 as ->. - eapply item_default_perm_valid in Hact; done. } - rewrite /= in HX4. subst. - eapply item_perms_valid in Heq. 2: done. - simpl in Heq. by ospecialize (Heq _). - - split; intros XX; eapply item_wf_item_lookup_active in XX; try done. - all: exfalso; destruct d; - (eapply disabled_in_practice_not_prot_init in X4; [done..| |by congruence]). - all: congruence. - - destruct d; simpl in Hr; inversion Hr; simplify_eq; simpl. - 2,4: done. all: exfalso; done. - Qed. - - Lemma tree_equals_protected_initialized d tr1 tr2 cid ev1 ev2 - (AllUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (AllUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (PND1 : protected_parents_not_disabled C tr1) - (PND2 : protected_parents_not_disabled C tr2) - (HCS1 : no_active_cousins C tr1) - (HCS2 : no_active_cousins C tr2) - (Hiwf1 : tree_items_compat_nexts tr1 ev1 ev2) - (Hiwf2 : tree_items_compat_nexts tr2 ev1 ev2) : - cid ∈ C → - tree_equal d tr1 tr2 → - tree_get_all_protected_tags_initialized_locs cid tr1 = - tree_get_all_protected_tags_initialized_locs cid tr2. - Proof. - intros Hcid Heq. eapply gset_leibniz. intros (tg&lst). - split; intros (it&Hlu&Hprot&Hinit)%tree_all_protected_initialized_elem_of; try done. - all: eapply tree_all_protected_initialized_elem_of; first done. - - edestruct (tree_equal_transfer_lookup_1 Heq Hlu) as (it'&Hit'&Heqit'). - exists it'. split; first done. - split; first by erewrite <- item_eq_up_to_C_same_iprot. - intros z. specialize (Hinit z). destruct (Heqit' z) as (Hproteq&Heqlu). - erewrite <- perm_eq_up_to_C_same_init. 2: done. - setoid_rewrite <- perm_eq_up_to_C_same_protected_active. 15: eassumption. 2-7: try done. - 1,4,5,6,7: done. - + eapply every_node_eqv_universal in Hiwf1. 2: eapply tree_lookup_to_exists_node, Hlu. - exact Hiwf1. - + eapply every_node_eqv_universal in Hiwf2. 2: eapply tree_lookup_to_exists_node, Hit'. - exact Hiwf2. - + by eexists cid. - - edestruct (tree_equal_transfer_lookup_2 Heq Hlu) as (it'&Hit'&Heqit'). - exists it'. split; first done. - split; first by erewrite item_eq_up_to_C_same_iprot. - intros z. specialize (Hinit z). destruct (Heqit' z) as (Hproteq&Heqlu). - erewrite perm_eq_up_to_C_same_init. 2: done. - setoid_rewrite perm_eq_up_to_C_same_protected_active. 15: eassumption. 2-7: done. - 1,4,5,6,7: done. - + eapply every_node_eqv_universal in Hiwf1. 2: eapply tree_lookup_to_exists_node, Hit'. - exact Hiwf1. - + eapply every_node_eqv_universal in Hiwf2. 2: eapply tree_lookup_to_exists_node, Hlu. - exact Hiwf2. - + rewrite Hproteq. by eexists cid. - Qed. - - - Lemma tree_equals_access_many_helper_2 tg (L : gmap Z _) tr1 tr1' tr2 - (Hwf1 : wf_tree tr1) - (Hwf2 : wf_tree tr2) - (PMI : parents_more_init tr2) - (ProtParentsNonDis2 : protected_parents_not_disabled C tr2) : - parents_more_active tr1 → parents_more_active tr2 → - no_active_cousins C tr1 → no_active_cousins C tr2 → - tree_equal Forwards tr1 tr2 → - tree_unique tg tr1 → - let fn := (λ tr, map_fold (λ l acc tr2, tr2 ≫= memory_access_nonchildren_only acc C tg (l, 1%nat)) (Some tr) L) in - fn tr1 = Some tr1' → - ∃ tr2', fn tr2 = Some tr2' ∧ tree_equal Forwards tr1' tr2'. - Proof. - intros X1 X2 X3 X4 Heq Hunq''. simpl. - map_fold_weak_ind L as off acc E Hnone Hfoo IH in tr1' Hunq''. - { simpl. intros [= ->]; by eexists. } - simpl. intros (tr1'''&H1&H2)%bind_Some. - specialize (IH _ Hunq'' H1) as (tr2'''&Htr2&HHtr2p). rewrite Hfoo Htr2 /=. - assert (tree_unique tg tr1''') as Hunq'''. - { rewrite /tree_unique. erewrite <- tree_access_many_helper_2. 1: exact Hunq''. exact H1. } - assert (wf_tree tr1''') as Hwf1'''. - { eapply preserve_tag_count_wf. 1: eapply tree_access_many_helper_2. 1: exact Hwf1. 1: apply H1. } - assert (wf_tree tr2''') as Hwf2'''. - { eapply preserve_tag_count_wf. 1: eapply tree_access_many_helper_2. 1: exact Hwf2. 1: apply Htr2. } - opose proof (tree_equal_allows_more_access_nonchildren_only _ _ _ _ _ HHtr2p Hunq''' _) as (trr&Htrr). - 1, 2: by apply wf_tree_tree_unique. 3: done. - 1: { eapply tree_access_many_protected_not_disabled_helper_2. 5: exact Htr2. 1,3,4: done. destruct Heq as (Hx&_). by eapply Hx, unique_exists. } - 1: { eapply tree_access_many_more_init_helper_2. 4: exact Htr2. 1,3: done. destruct Heq as (Hx&_). by eapply Hx, unique_exists. } - 1: by eapply mk_is_Some. - exists trr; split; first done. - eapply tree_equal_preserved_by_memory_access_nonchildren_only. - 9-10: done. 7: done. 7: by eapply unique_exists. - 1-2: by eapply wf_tree_tree_unique. - 1,3: eapply tree_access_many_more_active_helper_2; last done; first done; last done. - 2: eapply Heq. 1-2: by eapply unique_exists. - all: eapply tree_access_many_no_cousins_helper_2; last done; first done; last done. - 2: eapply Heq. 1-2: by eapply unique_exists. - Qed. - - Lemma tree_equals_access_many_helper_1 (E : list (tag * gmap Z _)) tr1 tr1' tr2 - (Hwf1 : wf_tree tr1) - (Hwf2 : wf_tree tr2) - (PMI2 : parents_more_init tr2) - (ProtParentsNonDis : protected_parents_not_disabled C tr2) : - parents_more_active tr1 → parents_more_active tr2 → - no_active_cousins C tr1 → no_active_cousins C tr2 → - tree_equal Forwards tr1 tr2 → - (∀ tg L, (tg, L) ∈ E → tree_unique tg tr1)→ - let fn := (λ tr, foldr (λ '(tg, L) tr, tr ≫= λ tr1, map_fold (λ l acc tr2, tr2 ≫= memory_access_nonchildren_only acc C tg (l, 1%nat)) (Some tr1) L) (Some tr) E) in - fn tr1 = Some tr1' → - ∃ tr2', fn tr2 = Some tr2' ∧ tree_equal Forwards tr1' tr2'. - Proof. - intros X1 X2 X3 X4 Heq Hunq. - induction E as [|(tg&init_locs) S IH] in tr1',Hunq|-*. - { simpl. intros [= ->]; by eexists. } - simpl. intros (tr1''&H1&H2)%bind_Some. - opose proof (IH _ _ H1) as (tr2''&Htr2&HHtr2); clear IH. - { intros ???. eapply Hunq. by right. } - rewrite Htr2 /=. pose proof Hunq as Hunq2. - ospecialize (Hunq tg init_locs _). 1: by left. revert H2. - eapply tree_equals_access_many_helper_2. - { eapply preserve_tag_count_wf. 1: eapply tree_access_many_helper_1. 1: exact Hwf1. 1: apply H1. } - { eapply preserve_tag_count_wf. 1: eapply tree_access_many_helper_1. 1: exact Hwf2. 1: exact Htr2. } - { eapply tree_access_many_more_init_helper_1. 4: exact Htr2. 1,3: done. intros ???. destruct Heq as (HH&_); eapply HH, unique_exists, Hunq2. by right. } - { eapply tree_access_many_protected_not_disabled_helper_1. 5: exact Htr2. 1,3,4: done. intros ???. destruct Heq as (HH&_); eapply HH, unique_exists, Hunq2. by right. } - 1,2: eapply tree_access_many_more_active_helper_1; last done; first done; last done; intros ???. - 2: eapply Heq. 1-2: eapply unique_exists, Hunq2; by right. - 1,2: eapply tree_access_many_no_cousins_helper_1; last done; first done; last done; intros ???. - 2: eapply Heq. 1-2: eapply unique_exists, Hunq2; by right. - { done. } - { rewrite /tree_unique. erewrite <- tree_access_many_helper_1. 1: exact Hunq. exact H1. } - Qed. - - Lemma tree_equals_access_all_protected_initialized' tr1 tr1' tr2 cid ev1 ev2 - (Hwf1 : wf_tree tr1) - (Hwf2 : wf_tree tr2) - (PMI : parents_more_init tr2) - (PMA1 : parents_more_active tr1) - (PMA2 : parents_more_active tr2) - (ProtParentsNonDis1 : protected_parents_not_disabled C tr1) - (ProtParentsNonDis2 : protected_parents_not_disabled C tr2) - (NA1 : no_active_cousins C tr1) - (NA2 : no_active_cousins C tr2) - (CC1 : tree_items_compat_nexts tr1 ev1 ev2) - (CC2 : tree_items_compat_nexts tr2 ev1 ev2) : - cid ∈ C → - tree_equal Forwards tr1 tr2 → - tree_access_all_protected_initialized C cid tr1 = Some tr1' → - ∃ tr2', tree_access_all_protected_initialized C cid tr2 = Some tr2' ∧ - tree_equal Forwards tr1' tr2'. - Proof. - intros Hc Heq. - rewrite /tree_access_all_protected_initialized. - erewrite <- (tree_equals_protected_initialized Forwards tr1 tr2); last done. - 2-3: by eapply wf_tree_tree_unique. 2-8: done. - eapply tree_equals_access_many_helper_1. 1-9: done. - {intros tg E. setoid_rewrite elem_of_elements. - intros (it&Hit&_)%tree_all_protected_initialized_elem_of. all: eapply wf_tree_tree_unique; try apply Hwf1. - by eapply lookup_implies_contains. } - Qed. - - Lemma apply_within_trees_lift d trs fn blk trs' : - wf_trees trs → - apply_within_trees fn blk trs = Some trs' → - (∀ tr tr', trs !! blk = Some tr → trs' !! blk = Some tr' → fn tr = Some tr' → tree_equal d tr tr') → - trees_equal d trs trs'. - Proof. - intros Hwf (tr&Htr&(tr'&Htr'&[= <-])%bind_Some)%bind_Some Heq. - intros bb. destruct (decide (bb = blk)) as [<-|Hne]. - - rewrite lookup_insert Htr. econstructor. eapply Heq. 1,3: done. by rewrite lookup_insert. - - rewrite lookup_insert_ne //. destruct (trs !! bb) eqn:HHeq. all: rewrite !HHeq. all: econstructor. - eapply tree_equal_reflexive. eapply wf_tree_tree_item_determined, Hwf, HHeq. - Qed. - - Lemma trees_equal_access_all_protected_initialized trs1 trs1' trs2 cid ev1 ev2 - (Hwf1 : wf_trees trs1) - (Hwf2 : wf_trees trs2) - (PMI : each_tree_parents_more_init trs2) - (PMA1 : each_tree_parents_more_active trs1) - (PMA2 : each_tree_parents_more_active trs2) - (ProtParentsNonDis1 : each_tree_protected_parents_not_disabled C trs1) - (ProtParentsNonDis2 : each_tree_protected_parents_not_disabled C trs2) - (NA1 : each_tree_no_active_cousins C trs1) - (NA2 : each_tree_no_active_cousins C trs2) - (CC1 : trees_compat_nexts trs1 ev1 ev2) - (CC2 : trees_compat_nexts trs2 ev1 ev2) : - cid ∈ C → - trees_equal Forwards trs1 trs2 → - trees_access_all_protected_initialized C cid trs1 = Some trs1' → - ∃ trs2', trees_access_all_protected_initialized C cid trs2 = Some trs2' ∧ - trees_equal Forwards trs1' trs2'. - Proof. - intros Hc Heq Htrapi. - epose proof (trees_access_all_protected_initialized_pointwise_1 _ _ _ _ Htrapi) as Htrapi1. - odestruct (trees_access_all_protected_initialized_pointwise_2 _ trs2) as (trs2'&Htrs2'). - { intros k. destruct (Htrapi1 k) as (HH'&_). intros tr2 Htr2. - specialize (Heq k). rewrite Htr2 in Heq. inversion Heq as [tr1 x1 Heqtr Htr1 e|]. subst x1. - destruct (HH' tr1) as (tr1'&Htr1'&HHtr1'); first done. - edestruct tree_equals_access_all_protected_initialized' as (tr2'&Htr2'&Heq'). - 13: exact Heqtr. 13: exact HHtr1'. 1: by eapply Hwf1. 1: by eapply Hwf2. - 11: by eexists. 1: by eapply PMI. 1: by eapply PMA1. 1: by eapply PMA2. 1: by eapply ProtParentsNonDis1. 1: by eapply ProtParentsNonDis2. - 1: by eapply NA1. 1: by eapply NA2. 1: by eapply CC1. 1: by eapply CC2. done. } - eexists; split; first done. - intros k. specialize (Heq k). - epose proof (trees_access_all_protected_initialized_pointwise_1 _ _ _ _ Htrs2' k) as (Htrapi2A&Htrapi2B). - specialize (Htrapi1 k) as (Htrapi1A&Htrapi1B). - inversion Heq as [tr1 tr2 Heqtr Htr1 Htr2|HNone1 HNone2]; last first. - - rewrite Htrapi1B // Htrapi2B //. econstructor. - - symmetry in Htr1,Htr2. - destruct (Htrapi1A _ Htr1) as (tr1'&Htr1'&Hrapi1'). destruct (Htrapi2A _ Htr2) as (tr2'&Htr2'&Hrapi2'). - rewrite Htr1' Htr2'. econstructor. - edestruct tree_equals_access_all_protected_initialized' as (tr2''&Htr2'u&Htr2'eq). - 14: exact Hrapi1'. 13: exact Heqtr. 1: by eapply Hwf1. 1: by eapply Hwf2. 1: by eapply PMI. 1: by eapply PMA1. 1: by eapply PMA2. 1: by eapply ProtParentsNonDis1. 1: by eapply ProtParentsNonDis2. - 1: by eapply NA1. 1: by eapply NA2. 1: by eapply CC1. 1: by eapply CC2. 1: done. - rewrite Hrapi2' in Htr2'u. injection Htr2'u as <-. done. - Qed. - - (* A bunch of extra conditions on the structure. - They are put in the same clause to simplify this theorem, but we will want - a higher-level lemma that derives these assumptions from their actual justification. *) - Definition tree_equal_asymmetric_read_pre_protected tr range it acc_tg (mode:bool) := - (∀ off, range'_contains range off → - let pp_acc := item_lookup it off in - pp_acc.(initialized) = PermInit ∧ pp_acc.(perm) ≠Disabled ∧ - ∀ tg' it', tree_lookup tr tg' it' → - let pp := item_lookup it' off in - let rd := rel_dec tr tg' acc_tg in (* flipped here so that it's correcty lined up with logical_state *) - match rd with - Foreign (Parent _) => pp.(initialized) = PermInit ∧ pp.(perm) ≠Disabled - | Foreign Cousin => pp.(perm) ≠Active | _ => True end ∧ - if mode then (rd = Child (Strict Immediate) → pp.(perm) = Disabled) else - (pp_acc.(perm) = Frozen ∧ (∀ i, rd = Child (Strict i) → pp.(perm) ≠Active))). - - (* Remember that the entire reason we have [trees_equal] in the first place - is to enable spurious reads. This is the lemma that verifies that after we - do a spurious read we get a [tree_equal]. A companion lemma (stating - that under certain circumstances the spurious read will succeed) will be proved - separately. - - The hypotheses are guided by the optimizations that we want to prove. - We can't (and don't plan to) do spurious reads anywhere, only on protected - tags. For now we require that the tag also doesn't have any Active - children. Both of these can be relaxed slightly, but a more general version - of this lemma will come only if actually required. - - Because we have nice properties of transitivity and reflexivity of [tree_equal] - already, the proof can be simplified by only considering the case where - before the asymmetric read the trees are identical. In other words we're going - to check that a tree is [tree_equal] to itself after a read. *) - Lemma tree_equal_asymmetric_read_protected - {d tr tr' acc_tg range it} (mode:bool) - (GloballyUnique : forall tg, tree_contains tg tr -> tree_unique tg tr) - : - (* Accessed tag must be in the tree and protected*) - tree_lookup tr acc_tg it -> - protector_is_active it.(iprot) C -> - tree_equal_asymmetric_read_pre_protected tr range it acc_tg mode -> - (* Under the above conditions if we do a spurious read and it succeeds - we get a [tree_equal] on the outcome. *) - memory_access AccessRead C acc_tg range tr = Some tr' -> - tree_equal d tr tr'. - Proof. - intros Lkup Protected TreeShapeProper Acc. - split; last split. - { intro tg. eapply access_preserves_tags. eassumption. } - { intros tg1 tg2. eapply access_same_rel_dec. eassumption. } - (* That was the easy part, helped by the fact that our initial configuration - is reflexivity instead of a more general instance of [tree_equal]. - Soon it will get more interesting. *) - intros tg0 Ex. - destruct (unique_implies_lookup (GloballyUnique _ Ex)) as [it0 Lookup0]. - exists it0. - assert (tree_unique tg0 tr') as Unq0'. { - erewrite <- tree_apply_access_preserve_unique; last eassumption. - apply GloballyUnique. assumption. - } - destruct (apply_access_spec_per_node (proj1 Lookup0) (proj2 Lookup0) Acc) as - (it0' & it0'Spec & Ex0' & Det0'). - symmetry in it0'Spec. - exists it0'. - split; first assumption. - split; first (split; assumption). - (* Now down to per-item reasoning *) - intro loc. - split; first (eapply item_apply_access_preserves_metadata; eassumption). - rewrite bind_Some in it0'Spec; destruct it0'Spec as (perms' & perms'Spec & [= <-]). - pose proof (mem_apply_range'_spec _ _ loc _ _ perms'Spec) as PerLoc. - clear perms'Spec. - assert (itag it0 = tg0) by (eapply tree_determined_specifies_tag; eapply Lookup0). - assert (itag it = acc_tg) by (eapply tree_determined_specifies_tag; eapply Lkup). - subst. - (* Finally the reasoning is per-location *) - destruct (decide _) as [HinRange|?]; last first. - { rewrite /item_lookup /= PerLoc. - constructor. } - destruct (TreeShapeProper _ HinRange) as (Htginit&Htgnondis&Hothers). - (* Keep digging until [apply_access_perm_inner] *) - destruct PerLoc as (perm' & perm'Lookup & perm'Spec). - pose proof Hothers as Hothers_pure. - ospecialize (Hothers _ _ Lookup0). - change (default _ _) with (item_lookup it0 loc) in perm'Spec. - rewrite {2}/item_lookup perm'Lookup /=. - rewrite bind_Some in perm'Spec; destruct perm'Spec as (tmperm & Inner & perm'Spec). - rewrite bind_Some in perm'Spec; destruct perm'Spec as (validated & MoreInit & EqPerm). - injection EqPerm; clear EqPerm; intros; subst. - rewrite rel_dec_flip2 in Hothers. - destruct Hothers as (Hothers&Hspecials). - destruct (rel_dec tr (itag it) (itag it0)) as [[]|[]] eqn:Hreldec. - - destruct mode. - + assert (∃ tg, tree_contains tg tr ∧ rel_dec tr tg (itag it) = Child (Strict Immediate) ∧ ParentChildIn tg (itag it0) tr) as (tgsw & Hin & Hswdec&Hpar). - { rewrite /rel_dec in Hreldec. destruct decide as [HP|HnP]; try done. destruct decide as [HP|?]; try done. - destruct HP as [Heq|HSP]. 1: exfalso; eapply HnP; by left. - eapply immediate_sandwich in HSP as HSP2. 2, 3: eapply GloballyUnique. 2: eapply Lkup. - destruct HSP2 as (tsw&Htsw&HPC). exists tsw. - assert (tree_contains tsw tr) as Hcont. - { eapply contains_child. 1: right; by eapply Immediate_is_StrictParentChild. - eapply Lkup. } - split_and!. 1: done. 2: done. - rewrite /rel_dec decide_True. - 2: right; by eapply Immediate_is_StrictParentChild. - rewrite decide_False. 1: by rewrite decide_True. - intros HH. eapply immediate_parent_not_child. 4: exact HH. 3: done. - all: eapply GloballyUnique. 1: eapply Lkup. done. } - assert (∃ itsw, tree_lookup tr tgsw itsw) as (itsw&Hitsw). - 1: eapply unique_implies_lookup, GloballyUnique, Hin. - specialize (Hothers_pure _ _ Hitsw). - destruct (apply_access_spec_per_node (proj1 Hitsw) (proj2 Hitsw) Acc) as - (itsw' & itsw'Spec & Hitsw'). - destruct Hothers_pure as (_&HH). ospecialize (HH _). 1: done. - eapply (perm_eq_up_to_C_disabled_parent _ _ _ _ _ _ tgsw). 3: rewrite /= most_init_comm //=. - * econstructor. 2: done. 1: rewrite /rel_dec decide_True //. - destruct (item_lookup itsw loc) as [[] pp] eqn:HHH; simpl in *; subst pp. - 1: econstructor 1. econstructor 2. econstructor 1. - * econstructor. 1: erewrite <- access_same_rel_dec. 2: eassumption. 1: rewrite /rel_dec decide_True //. - 1: exact Hitsw'. symmetry in itsw'Spec. - eapply bind_Some in itsw'Spec as (psw&Hsw&[= Hitsweq]). - pose proof (mem_apply_range'_spec _ _ loc _ _ Hsw) as PerLocSW. - rewrite decide_True // in PerLocSW. destruct PerLocSW as (p & HPP & Hacc). - rewrite /= /apply_access_perm /apply_access_perm_inner /= in Hacc. - change (default _ _) with (item_lookup itsw loc) in Hacc. - assert (itag itsw = tgsw) as <- by by eapply tree_lookup_correct_tag. - rewrite rel_dec_flip2 Hswdec /= HH /= most_init_comm /= in Hacc. - rewrite /item_lookup /= -Hitsweq HPP /=. - destruct (item_lookup itsw loc) as [ini prm] eqn:Heq; simpl in *; subst prm. - edestruct (bool_decide (protector_is_active (iprot itsw) C)), ini in Hacc; simpl in Hacc; try discriminate Hacc; injection Hacc as <-. - all: try econstructor 1. all: econstructor 2; econstructor 1. - + rewrite /apply_access_perm_inner /= in Inner. rewrite /= most_init_comm /=. - destruct Hspecials as (Hfrz&Hnact). - destruct (item_lookup it0 loc) as [ini [cfl| | | |]] eqn:Hperm. - 2,4,5: by (destruct ini, (bool_decide (protector_is_active (iprot it0) C)); simpl in *; simplify_eq; econstructor 1). - 2: exfalso; by eapply Hnact. - simpl in *. assert (∃ cfl', validated = Reserved cfl') as (cfl'&->). - { destruct ini, cfl, (bool_decide (protector_is_active (iprot it0) C)); simpl in *; eexists; simplify_eq; done. } - destruct (apply_access_spec_per_node (proj1 Lkup) (proj2 Lkup) Acc) as - (it' & it'Spec & Hit'). symmetry in it'Spec. - eapply bind_Some in it'Spec as (pit&Hpit&[= Hiteq]). - pose proof (mem_apply_range'_spec _ _ loc _ _ Hpit) as PerLoc. - rewrite decide_True // in PerLoc. destruct PerLoc as (p & HPP & Hacc). - rewrite /= /apply_access_perm /apply_access_perm_inner /= in Hacc. - change (default _ _) with (item_lookup it loc) in Hacc. - assert (itag it' = itag it) as Hit by by eapply tree_lookup_correct_tag. - rewrite rel_dec_refl Hfrz /= most_init_comm /= in Hacc. - rewrite Tauto.if_same /= in Hacc. injection Hacc as <-. - eapply perm_eq_up_to_C_frozen_parent with (witness_tg := itag it). destruct d. - * econstructor. 1: rewrite rel_dec_flip2 Hreldec //. 1: exact Lkup. 1: done. 1: done. - * econstructor. - { erewrite <- access_same_rel_dec. 2: done. rewrite rel_dec_flip2 Hreldec //. } - { eapply Hit'. } - all: rewrite /item_lookup -Hiteq /= HPP /= //. - - rewrite /= most_init_comm /=. - rewrite /apply_access_perm_inner /= in Inner. - destruct (item_lookup it0 loc) as [[] [[]| | | |]] eqn:Hperm, (bool_decide (protector_is_active (iprot it0) C)) eqn:Hprot; simpl in *. - all: try by (simplify_eq; econstructor 1). - 1-2: simplify_eq; econstructor 2; - [by eapply bool_decide_eq_true_1| |econstructor 1]. - 1-2: eapply (pseudo_conflicted_cousin_init _ _ _ (itag it) it); - [rewrite rel_dec_flip2 Hreldec //|done..]. - - destruct Hothers as (Hinit&Hndis). - rewrite /apply_access_perm_inner /= in Inner. - destruct (item_lookup it0 loc) as [[] pp] eqn:Hperm. 2: done. - assert (pp = tmperm) as ->. - { simpl in *. destruct pp; simplify_eq; done. } - rewrite /= in MoreInit|-*. - destruct tmperm, (bool_decide (protector_is_active (iprot it0) C)); simpl in MoreInit. - all: try done. all: simplify_eq; econstructor 1. - - simpl in *. assert (itag it = itag it0) as Htageq. - { rewrite /rel_dec in Hreldec. do 2 (destruct decide; try done). - eapply mutual_parent_child_implies_equal. 1: done. 1: eapply Lkup. all: done. } - assert (it = it0) as ->. - { eapply tree_determined_unify. 1, 2: eapply Lkup. rewrite Htageq. eapply Lookup0. } - rewrite Htginit in MoreInit|-*. - rewrite bool_decide_true // /= in MoreInit. - destruct (item_lookup it0 loc) as [[] pp] eqn:Hperm. 2: done. - destruct pp; try done. all: repeat (simpl in *; simplify_eq); by econstructor 1. - Qed. - - (* We can also do symmetric writes, provided we have sufficiently strong preconditions, - which include being protected. *) - Definition tree_equal_asymmetric_write_pre_protected tr range it acc_tg := - (∀ off, range'_contains range off → - let pp_acc := item_lookup it off in - pp_acc.(initialized) = PermInit ∧ pp_acc.(perm) = Active ∧ - ∀ tg' it', tree_lookup tr tg' it' → - let pp := item_lookup it' off in - let rd := rel_dec tr tg' acc_tg in (* flipped here so that it's correcty lined up with logical_state *) - match rd with - | Child (Strict Immediate) => pp.(perm) = Disabled - | Child _ => True - | Foreign (Parent _) => pp.(initialized) = PermInit ∧ pp.(perm) = Active (* this follows from state_wf *) - | Foreign Cousin => match pp.(perm) with Disabled => True | ReservedIM => ¬ protector_is_active it'.(iprot) C (* never occurs *) | _ => pp.(initialized) = PermLazy end end). - - Lemma disabled_is_disabled x1 x2 x3 x4 pp : perm pp = Disabled → is_disabled x1 x2 x3 pp x4. - Proof. - destruct pp as [[] pp]; simpl; intros ->. - 1: econstructor 1. - econstructor 2. econstructor 1. - Qed. - - Lemma tree_equal_asymmetric_write_protected - {d tr tr' acc_tg range it} - (GloballyUnique : forall tg, tree_contains tg tr -> tree_unique tg tr) - : - (* Accessed tag must be in the tree and protected*) - tree_lookup tr acc_tg it -> - protector_is_active it.(iprot) C -> - tree_equal_asymmetric_write_pre_protected tr range it acc_tg -> - (* Under the above conditions if we do a spurious read and it succeeds - we get a [tree_equal] on the outcome. *) - memory_access AccessWrite C acc_tg range tr = Some tr' -> - tree_equal d tr tr'. - Proof. - intros Lkup Protected TreeShapeProper Acc. - split; last split. - { intro tg. eapply access_preserves_tags. eassumption. } - { intros tg1 tg2. eapply access_same_rel_dec. eassumption. } - (* That was the easy part, helped by the fact that our initial configuration - is reflexivity instead of a more general instance of [tree_equal]. - Soon it will get more interesting. *) - intros tg0 Ex. - destruct (unique_implies_lookup (GloballyUnique _ Ex)) as [it0 Lookup0]. - exists it0. - assert (tree_unique tg0 tr') as Unq0'. { - erewrite <- tree_apply_access_preserve_unique; last eassumption. - apply GloballyUnique. assumption. - } - destruct (apply_access_spec_per_node (proj1 Lookup0) (proj2 Lookup0) Acc) as - (it0' & it0'Spec & Ex0' & Det0'). - symmetry in it0'Spec. - exists it0'. - split; first assumption. - split; first (split; assumption). - (* Now down to per-item reasoning *) - intro loc. - split; first (eapply item_apply_access_preserves_metadata; eassumption). - rewrite bind_Some in it0'Spec; destruct it0'Spec as (perms' & perms'Spec & [= <-]). - pose proof (mem_apply_range'_spec _ _ loc _ _ perms'Spec) as PerLoc. - clear perms'Spec. - assert (itag it0 = tg0) by (eapply tree_determined_specifies_tag; eapply Lookup0). - assert (itag it = acc_tg) by (eapply tree_determined_specifies_tag; eapply Lkup). - subst. - (* Finally the reasoning is per-location *) - destruct (decide _) as [HinRange|?]; last first. - { rewrite /item_lookup /= PerLoc. - constructor. } - destruct (TreeShapeProper _ HinRange) as (Htginit&Htgactive&Hothers). - (* Keep digging until [apply_access_perm_inner] *) - destruct PerLoc as (perm' & perm'Lookup & perm'Spec). - pose proof Hothers as Hothers_pure. - ospecialize (Hothers _ _ Lookup0). - change (default _ _) with (item_lookup it0 loc) in perm'Spec. - rewrite {2}/item_lookup perm'Lookup /=. - rewrite bind_Some in perm'Spec; destruct perm'Spec as (tmperm & Inner & perm'Spec). - rewrite bind_Some in perm'Spec; destruct perm'Spec as (validated & MoreInit & EqPerm). - injection EqPerm; clear EqPerm; intros; subst. - rewrite rel_dec_flip2 /= in Hothers. - destruct (rel_dec tr (itag it) (itag it0)) as [[]|[]] eqn:Hreldec; simpl in Hothers. - - assert (∃ tg, tree_contains tg tr ∧ rel_dec tr tg (itag it) = Child (Strict Immediate) ∧ ParentChildIn tg (itag it0) tr) as (tgsw & Hin & Hswdec&Hpar). - { rewrite /rel_dec in Hreldec. destruct decide as [HP|HnP]; try done. destruct decide as [HP|?]; try done. - destruct HP as [Heq|HSP]. 1: exfalso; eapply HnP; by left. - eapply immediate_sandwich in HSP as HSP2. 2, 3: eapply GloballyUnique. 2: eapply Lkup. - destruct HSP2 as (tsw&Htsw&HPC). exists tsw. - assert (tree_contains tsw tr) as Hcont. - { eapply contains_child. 1: right; by eapply Immediate_is_StrictParentChild. - eapply Lkup. } - split_and!. 1: done. 2: done. - rewrite /rel_dec decide_True. - 2: right; by eapply Immediate_is_StrictParentChild. - rewrite decide_False. 1: by rewrite decide_True. - intros HH. eapply immediate_parent_not_child. 4: exact HH. 3: done. - all: eapply GloballyUnique. 1: eapply Lkup. done. } - assert (∃ itsw, tree_lookup tr tgsw itsw) as (itsw&Hitsw). - 1: eapply unique_implies_lookup, GloballyUnique, Hin. - specialize (Hothers_pure _ _ Hitsw). - destruct (apply_access_spec_per_node (proj1 Hitsw) (proj2 Hitsw) Acc) as - (itsw' & itsw'Spec & Hitsw'). rewrite Hswdec /= in Hothers_pure. - eapply (perm_eq_up_to_C_disabled_parent _ _ _ _ _ _ tgsw). 3: rewrite /= most_init_comm //=. - * econstructor. 2: done. 1: rewrite /rel_dec decide_True //. eapply disabled_is_disabled, Hothers_pure. - * econstructor. 1: erewrite <- access_same_rel_dec. 2: eassumption. 1: rewrite /rel_dec decide_True //. - 1: exact Hitsw'. symmetry in itsw'Spec. - eapply bind_Some in itsw'Spec as (psw&Hsw&[= Hitsweq]). - pose proof (mem_apply_range'_spec _ _ loc _ _ Hsw) as PerLocSW. - rewrite decide_True // in PerLocSW. destruct PerLocSW as (p & HPP & Hacc). - rewrite /= /apply_access_perm /apply_access_perm_inner /= in Hacc. - change (default _ _) with (item_lookup itsw loc) in Hacc. - assert (itag itsw = tgsw) as <- by by eapply tree_lookup_correct_tag. - rewrite rel_dec_flip2 Hswdec /= Hothers_pure /= in Hacc. - rewrite /item_lookup /= -Hitsweq HPP /=. - repeat (case_match; simpl in *; try done; simplify_eq). - all: by eapply disabled_is_disabled. - - rewrite /= most_init_comm /=. - rewrite /apply_access_perm_inner /= in Inner. - eapply rel_dec_flip in Hreldec. - destruct (item_lookup it0 loc) as [[] [[]| | | |]] eqn:Hperm, (bool_decide (protector_is_active (iprot it0) C)) eqn:Hprot; simpl in *. - all: try by (simplify_eq; first [done | econstructor 1]). - all: try by eapply bool_decide_eq_true_1 in Hprot. - all: injection Inner as <-; injection MoreInit as <-. - all: econstructor 4; last econstructor 1. - all: econstructor 2; [exact Hreldec|exact Lkup|done|destruct (item_lookup it loc); simpl in *; congruence| ]. - all: intros [=]. all: by eapply bool_decide_eq_true_1. - - destruct Hothers as (Hini&Hact). - rewrite /apply_access_perm_inner /= in Inner. - destruct (item_lookup it0 loc) as [ini pp] eqn:Hperm. - simpl in Hini, Hact. subst ini pp. simpl in Inner. simplify_eq. simpl in MoreInit. - destruct (bool_decide (protector_is_active (iprot it0) C)); simpl in MoreInit|-*; simplify_eq. - all: econstructor 1. - - simpl in *. assert (itag it = itag it0) as Htageq. - { rewrite /rel_dec in Hreldec. do 2 (destruct decide; try done). - eapply mutual_parent_child_implies_equal. 1: done. 1: eapply Lkup. all: done. } - assert (it = it0) as ->. - { eapply tree_determined_unify. 1, 2: eapply Lkup. rewrite Htageq. eapply Lookup0. } - rewrite Htginit in MoreInit|-*. rewrite Htgactive in Inner. simplify_eq. - rewrite bool_decide_true // /= in MoreInit. simplify_eq. - destruct (item_lookup it0 loc) as [ii pp]. simpl in *; subst ii pp. econstructor 1. - Qed. - - Lemma rel_dec_equal_ParentChildIn_equiv tr1 tr2 : - (∀ tg, tree_contains tg tr1 ↔ tree_contains tg tr2) → - (∀ tg1 tg2, rel_dec tr1 tg1 tg2 = rel_dec tr2 tg1 tg2) → - ∀ tg1 tg2, (ParentChildIn tg1 tg2 tr1 ↔ ParentChildIn tg1 tg2 tr2) ∧ (ImmediateParentChildIn tg1 tg2 tr1 ↔ ImmediateParentChildIn tg1 tg2 tr2). - Proof. - intros Hcont H tg1 tg2. - specialize (H tg2 tg1). - rewrite /rel_dec in H. destruct (decide (ParentChildIn tg1 tg2 tr1)) as [H1|H1]; last first. - all: destruct (decide (ParentChildIn tg1 tg2 tr2)) as [H2|H2]; try done. - all: split; first tauto. - - split; intros H3%Immediate_is_StrictParentChild; exfalso. 1: eapply H1. 2: eapply H2. all: by right. - - destruct (decide (tree_contains tg1 tr1)) as [Hin|Hnin]; last first. - { split; intros _; eapply ImmediateParentChildIn_parent_not_in; last done. - by setoid_rewrite <- Hcont. } - destruct (decide (tg1 = tg2)) as [->|Hne]. - { split; intros H3%Immediate_is_StrictParentChild; exfalso; (eapply strict_parent_self_impossible; last done). - 2: rewrite <- Hcont. all: done. } - destruct H1 as [?|H1]; first done. - destruct H2 as [?|H2]; first done. - rewrite decide_False in H. 2: { intros [?|H3]; first done. eapply strict_parent_self_impossible; first done. by eapply StrictParentChild_transitive. } - rewrite (decide_False This) in H. 2: { intros [?|H3]; first done. setoid_rewrite Hcont in Hin. eapply strict_parent_self_impossible; first done. by eapply StrictParentChild_transitive. } - destruct (decide (ImmediateParentChildIn tg1 tg2 tr1)), (decide (ImmediateParentChildIn tg1 tg2 tr2)); done. - Qed. - - Lemma rel_dec_equal_ParentChildIn_equiv_lift tr1 tr2 : - (∀ tg, tree_contains tg tr1 ↔ tree_contains tg tr2) → - (∀ tg1 tg2, rel_dec tr1 tg1 tg2 = rel_dec tr2 tg1 tg2) → - (∀ tg1 tg2, ParentChildIn tg1 tg2 tr1 ↔ ParentChildIn tg1 tg2 tr2) ∧ - (∀ tg1 tg2, StrictParentChildIn tg1 tg2 tr1 ↔ StrictParentChildIn tg1 tg2 tr2) ∧ - (∀ tg1 tg2, ImmediateParentChildIn tg1 tg2 tr1 ↔ ImmediateParentChildIn tg1 tg2 tr2). - Proof. - intros H1 H2. - epose proof (rel_dec_equal_ParentChildIn_equiv _ _ H1 H2) as H. split_and!. - 1, 3: eapply H. - intros tg1 tg2. - destruct (decide (tree_contains tg1 tr1)) as [H3|H3]; last first. - all: epose proof H3 as H3'; setoid_rewrite H1 in H3'. - { split; intros _; rewrite /StrictParentChildIn; eapply every_subtree_eqv_universal. - all: intros br Hex Htg; exfalso. 1: eapply H3'. 2: eapply H3. - all: eapply exists_node_iff_exists_root. - all: eapply exists_subtree_eqv_existential; eexists. - all: split; first done; done. - all: split; first eapply exists_node_iff_exists_root. } - destruct (decide (tg1 = tg2)) as [->|Hne]. - { split; intros []%strict_parent_self_impossible; done. } - destruct (H tg1 tg2) as ((HH1&HH2)&_). - split; intros Hc. - - destruct HH1 as [?|HH1]; try done. by right. - - destruct HH2 as [?|HH2]; try done. by right. - Qed. - - Lemma tree_equal_create_child d tr1 tr2 tr1' tg_new tg_old pk im rk cid ev2 : - wf_tree tr1 → wf_tree tr2 → - tree_items_compat_nexts tr1 tg_new ev2 → tree_items_compat_nexts tr2 tg_new ev2 → - (cid < ev2)%nat → - tree_contains tg_old tr1 → - ¬ tree_contains tg_new tr1 → - tree_equal d tr1 tr2 → - create_child C tg_old tg_new pk im rk cid tr1 = Some tr1' → - ∃ tr2', create_child C tg_old tg_new pk im rk cid tr2 = Some tr2' ∧ - tree_equal d tr1' tr2'. - Proof. - intros Hwf1 Hwf2 Hiwf1 Hiwf2 Hcidwf. - intros Hcontains1 Hnotcont1 (H1&H2&H3) (it_new&Hit_new&[= <-])%bind_Some. - assert (itag it_new = tg_new) as Htgnew by by eapply new_item_has_tag. - assert (tg_old ≠tg_new) as Htgsne by (intros ->; firstorder). - pose proof Hcontains1 as Hcontains2. setoid_rewrite H1 in Hcontains2. - pose proof Hnotcont1 as Hnotcont2. setoid_rewrite H1 in Hnotcont2. - epose proof create_new_item_wf _ _ _ _ _ _ _ Hcidwf Hit_new as Hitemwf. - opose proof (insert_child_wf C _ _ _ _ _ _ _ _ _ _ Hitemwf Hit_new _ Hiwf1 Hwf1) as (_&Hwf1'). - 1: rewrite /create_child Hit_new //. - opose proof (insert_child_wf C _ _ _ _ _ _ _ _ _ _ Hitemwf Hit_new _ Hiwf2 Hwf2) as (_&Hwf2'). - 1: rewrite /create_child Hit_new //. - eexists. split. - 1: rewrite /create_child Hit_new //. - pose proof (rel_dec_equal_ParentChildIn_equiv_lift _ _ H1 H2) as (H2A&H2B&H2C). - split_and!. - - intros tg. destruct (decide (tg = tg_new)) as [->|Hne]. - + split; (intros _; eapply insert_true_produces_exists; [done|]); assumption. - + split; (intros H%insert_false_infer_exists; last congruence); eapply insert_preserves_exists, H1, H. - - eapply same_parent_childs_agree; intros tg tg'. - + destruct (decide (tg = tg_new)) as [->|Hne], (decide (tg' = tg_new)) as [->|Hne']. - * split; intros _; by left. - * subst tg_new. split; (intros [|Hc]; first done); exfalso; (eapply inserted_not_strict_parent; [| |exact Hc]; done). - * subst tg_new. destruct (decide (tg = tg_old)) as [->|Hneold]. - 1: split; intros _; eapply insert_produces_ParentChild; done. - split; (intros [|Hc]; first done). - all: eapply insert_produces_minimal_ParentChild in Hc; [|done..]. - all: eapply ParentChild_transitive; last by eapply insert_produces_ParentChild. - all: right; setoid_rewrite <- insert_eqv_strict_rel; [|done..]. - 1: by setoid_rewrite <- H2B. 1: by setoid_rewrite H2B. - * subst tg_new. split; (intros [->|Hc]; [by left|right]). - all: setoid_rewrite <- insert_eqv_strict_rel; [|done..]. - all: eapply H2B. - all: setoid_rewrite -> insert_eqv_strict_rel; first done; done. - + destruct (decide (tg = tg_new)) as [->|Hne], (decide (tg' = tg_new)) as [->|Hne']. - * subst tg_new. split; intros H; exfalso; (eapply immediate_parent_child_not_equal; [..|done|done]). - 1-2: eapply Hwf1'. 3-4: eapply Hwf2'. - all: eapply insert_true_produces_exists; first done; done. - * subst tg_new. split; (intros Hc%Immediate_is_StrictParentChild); exfalso; (eapply inserted_not_strict_parent; [| |exact Hc]; done). - * subst tg_new. destruct (decide (tg = tg_old)) as [->|Hneold]. - 1: split; intros _; eapply insert_produces_ImmediateParentChild; done. - destruct (decide (tree_contains tg tr1)) as [Htgin|Htgnin]; last first. - { split; intros _; eapply ImmediateParentChildIn_parent_not_in. - all: intros Hc%remove_false_preserves_exists; last done. - all: eapply Htgnin. 1: eapply H1. all: eapply Hc. } - split; intros Hc; exfalso. - all: eapply ImmediateParentChild_of_insert_is_parent in Hc; [done|done|..|done]. - 1: done. by eapply H1. - * subst tg_new. setoid_rewrite <- insert_eqv_imm_rel. 1: apply H2C. - all: done. - - intros tg Hcont. subst tg_new. - destruct (decide (tg = itag it_new)) as [->|Hne]. - { exists it_new, it_new. split_and!. - 1-2: split; first by eapply insert_true_produces_exists. - 1-2: by eapply inserted_determined. - eapply item_eq_up_to_C_reflexive. } - eapply remove_false_preserves_exists in Hcont. 2: done. - destruct (H3 tg Hcont) as (it1&it2&Hlu1&Hlu2&Hequptoc). - exists it1, it2. split_and!. - 1-2: destruct Hlu1, Hlu2. - 1-2: split; first by eapply insert_preserves_exists. - 1-2: setoid_rewrite <- insert_true_preserves_every; done. - intros l. specialize (Hequptoc l) as (Heq1&Heq2). - split; first done. - inversion Heq2 as [|pi c1 c2 Hi1 Hi2 Hi3 Hi4 Hi5| |p1 p2 Hi2 Hi3 Hi4 Hi5|witness_tg ? ? Dis1 Dis2|??? witness_tg Frz1|p1 p2 ini Hd]; simplify_eq. - + by econstructor 1. - + destruct Hlu1 as (Hlu1A&Hlu1B), Hlu2 as (Hlu2A&Hlu2B). - pose proof Hcont as Hcont2. setoid_rewrite H1 in Hcont2. econstructor 2. 1: done. - * inversion Hi2 as [|tg_cs it_cs Hii1 Hii2 Hii3 Hii4 Hii5 Hii6]; simplify_eq; first by econstructor 1. - destruct Hii2 as [HA HB]. - econstructor 2. 3-5: done. - 2: { split. 1: by eapply insert_preserves_exists. - setoid_rewrite <- insert_true_preserves_every; first done. - intros <-. done. } - rewrite /rel_dec in Hii1|-*. - destruct (decide (ParentChildIn tg_cs tg tr1)) as [|HnPC]; first done. - destruct (decide (ParentChildIn tg tg_cs tr1)) as [|HnPC2]; first done. - rewrite decide_False; first rewrite decide_False //; last first. - -- intros [|Hc]; eapply HnPC; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - -- intros [|Hc]; eapply HnPC2; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - * inversion Hi3 as [|tg_cs it_cs Hii1 Hii2 Hii3 Hii4 Hii5 Hii6]; simplify_eq; first by econstructor 1. - destruct Hii2 as [HA HB]. - econstructor 2. 3-5: done. - 2: { split. 1: by eapply insert_preserves_exists. - setoid_rewrite <- insert_true_preserves_every; first done. - intros <-. done. } - rewrite /rel_dec in Hii1|-*. - destruct (decide (ParentChildIn tg_cs tg tr2)) as [|HnPC]; first done. - destruct (decide (ParentChildIn tg tg_cs tr2)) as [|HnPC2]; first done. - rewrite decide_False; first rewrite decide_False //; last first. - -- intros [|Hc]; eapply HnPC; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - -- intros [|Hc]; eapply HnPC2; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - + by econstructor 3. - + destruct Hlu1 as (Hlu1A&Hlu1B), Hlu2 as (Hlu2A&Hlu2B). - pose proof Hcont as Hcont2. setoid_rewrite H1 in Hcont2. econstructor 4. - * inversion Hi2 as [|tg_cs it_cs X1 X2 Hii1 Hii2 Hii3 Hii4]; simplify_eq; first by econstructor 1. - destruct Hii2 as [HA HB]. - econstructor 2. 3-5: done. - 2: { split. 1: by eapply insert_preserves_exists. - setoid_rewrite <- insert_true_preserves_every; first done. - intros <-. done. } - rewrite /rel_dec in Hii1|-*. - destruct (decide (ParentChildIn tg_cs tg tr1)) as [|HnPC]; first done. - destruct (decide (ParentChildIn tg tg_cs tr1)) as [|HnPC2]; first done. - rewrite decide_False; first rewrite decide_False //; last first. - -- intros [|Hc]; eapply HnPC; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - -- intros [|Hc]; eapply HnPC2; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - * inversion Hi3 as [|tg_cs it_cs X1 X2 Hii1 Hii2 Hii3 Hii4]; simplify_eq; first by econstructor 1. - destruct Hii2 as [HA HB]. - econstructor 2. 3-5: done. - 2: { split. 1: by eapply insert_preserves_exists. - setoid_rewrite <- insert_true_preserves_every; first done. - intros <-. done. } - rewrite /rel_dec in Hii1|-*. - destruct (decide (ParentChildIn tg_cs tg tr2)) as [|HnPC]; first done. - destruct (decide (ParentChildIn tg tg_cs tr2)) as [|HnPC2]; first done. - rewrite decide_False; first rewrite decide_False //; last first. - -- intros [|Hc]; eapply HnPC; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - -- intros [|Hc]; eapply HnPC2; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - + econstructor 5. - * eapply disabled_in_practice_create_child_irreversible. - 5: rewrite /create_child; erewrite Hit_new; done. - -- lia. - -- inversion Dis1 as [it_witness ?? LuWitness]. - pose proof (tree_determined_specifies_tag _ _ _ (proj1 LuWitness) (proj2 LuWitness)) as itag_witness_spec. - pose proof ((proj1 (every_node_iff_every_lookup (wf_tree_tree_item_determined _ Hwf1)) Hiwf1 witness_tg it_witness ltac:(assumption)).(item_tag_valid _ _ _) witness_tg itag_witness_spec). - enough (itag it_new ≠witness_tg) by eassumption. - lia. - -- eassumption. - -- eassumption. - * eapply disabled_in_practice_create_child_irreversible. - 5: rewrite /create_child; erewrite Hit_new; done. - -- lia. - -- inversion Dis1 as [it_witness ?? LuWitness]. - pose proof (tree_determined_specifies_tag _ _ _ (proj1 LuWitness) (proj2 LuWitness)) as itag_witness_spec. - pose proof ((proj1 (every_node_iff_every_lookup (wf_tree_tree_item_determined _ Hwf1)) Hiwf1 witness_tg it_witness ltac:(assumption)).(item_tag_valid _ _ _) witness_tg itag_witness_spec). - enough (itag it_new ≠witness_tg) by eassumption. - lia. - -- eassumption. - -- eassumption. - * auto. - + econstructor 6; destruct d. - * eapply frozen_in_practice_create_child_irreversible. - 4: rewrite /create_child; erewrite Hit_new; done. - -- lia. - -- inversion Frz1 as [it_witness ?? LuWitness]. - pose proof (tree_determined_specifies_tag _ _ _ (proj1 LuWitness) (proj2 LuWitness)) as itag_witness_spec. - pose proof ((proj1 (every_node_iff_every_lookup (wf_tree_tree_item_determined _ Hwf1)) Hiwf1 witness_tg it_witness ltac:(assumption)).(item_tag_valid _ _ _) witness_tg itag_witness_spec). - enough (itag it_new ≠witness_tg) by eassumption. - lia. - -- eassumption. - * eapply frozen_in_practice_create_child_irreversible. - 4: rewrite /create_child; erewrite Hit_new; done. - -- lia. - -- inversion Frz1 as [it_witness ?? LuWitness]. - pose proof (tree_determined_specifies_tag _ _ _ (proj1 LuWitness) (proj2 LuWitness)) as itag_witness_spec. - pose proof ((proj1 (every_node_iff_every_lookup (wf_tree_tree_item_determined _ Hwf2)) Hiwf2 witness_tg it_witness ltac:(assumption)).(item_tag_valid _ _ _) witness_tg itag_witness_spec). - enough (itag it_new ≠witness_tg) by eassumption. - lia. - -- eassumption. - + econstructor 7. done. - Qed. - - Lemma trees_equal_create_child d trs1 trs2 trs1' blk tg_new tg_old pk im rk cid nxtc : - wf_trees trs1 → wf_trees trs2 → - trees_compat_nexts trs1 tg_new nxtc → trees_compat_nexts trs2 tg_new nxtc → - (cid < nxtc)%nat → - trees_contain tg_old trs1 blk → - ¬ trees_contain tg_new trs1 blk → - trees_equal d trs1 trs2 → - apply_within_trees (create_child C tg_old tg_new pk im rk cid) blk trs1 = Some trs1' → - ∃ trs2', apply_within_trees (create_child C tg_old tg_new pk im rk cid) blk trs2 = Some trs2' ∧ - trees_equal d trs1' trs2'. - Proof. - intros Hwf1 Hwf2 Hiwf1 Hiwf2 Hcidwf Hcont Hncont Heq. - intros (tr1&Htr1&(tr1'&Htr1'&[= <-])%bind_Some)%bind_Some. - eapply bind_Some in Htr1' as HH. destruct HH as (it&Hit&[= Htrit]). - epose proof (Heq blk) as HeqblkI. - inversion HeqblkI as [t1x tr2 Heqblk Heq1x Htr2|]; simplify_eq; last congruence. - symmetry in Htr2. assert (t1x = tr1) as -> by congruence. clear Heq1x. - eapply tree_equal_create_child in Htr1' as (tr2'&Htr2'&Heqtr). - - eexists. rewrite /apply_within_trees /= Htr2 /=. - split; first by rewrite /create_child Hit. - intros blk'. destruct (decide (blk = blk')) as [->|Hne]. - + rewrite !lookup_insert. econstructor. - eapply bind_Some in Htr2' as HH. destruct HH as (it2&Hit2&[= <-]). - enough (it = it2) as -> by by eapply Heqtr. - congruence. - + rewrite !lookup_insert_ne //. - - by eapply Hwf1. - - by eapply Hwf2. - - by eapply Hiwf1. - - by eapply Hiwf2. - - done. - - by rewrite /trees_contain /trees_at_block Htr1 in Hcont. - - by rewrite /trees_contain /trees_at_block Htr1 in Hncont. - - done. - Qed. - - Lemma perm_eq_up_to_C_trans {tr1 tr2 tr3 tg l cid perm1 perm2 perm3} : - protected_parents_not_disabled C tr2 → - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - (∀ tg, tree_contains tg tr1 → tree_unique tg tr1) → - parents_more_active tr2 → - no_active_cousins C tr2 → - parents_more_active tr1 → - no_active_cousins C tr1 → - tree_equal Forwards tr1 tr2 → - tree_equal Forwards tr2 tr3 → - perm_eq_up_to_C tr1 tr2 tg l cid Forwards perm1 perm2 → - perm_eq_up_to_C tr2 tr3 tg l cid Forwards perm2 perm3 → - perm_eq_up_to_C tr1 tr3 tg l cid Forwards perm1 perm3. - Proof. - intros Hpnd Hunq1 Hunq2 Hpma1 Hnac1 Hpma2 Hnac2 Heq12 Heq23 EqC1 EqC2. - inversion EqC1 as [pp1|ini1 confl1 confl2 Hprot HP1 HP2|ini1 confl1 confl2 HnoProt|p1 p2 HP1 HP2|wit_tg lp1 lp2 Hdip1 Hdip2 Hini|ini1 confl1 confl2 wit_tg HF|p1 p2 ini Hd]; simplify_eq; - inversion EqC2 as [pp1'|ini1' confl1' confl2' Hprot' HP1' HP2'|ini1' confl1' confl2' HnoProt'|p1' p2' HP1' HP2'|wit_tg' lp1 lp2 Hdip1' Hdip2' Hini'|ini1' confl1' confl2' wit_tg' HF'|p1' p2' ini' Hd']; simplify_eq. - (* easy case: perm1 = perm2 *) - + econstructor 1. - + econstructor 2. 1: done. 2: done. - eapply tree_equal_transfer_pseudo_conflicted. 1: done. 1: done. 1: done. - 1: by eapply tree_equal_sym. done. - + by econstructor 3. - + econstructor 4. 2: done. - eapply tree_equal_transfer_pseudo_disabled. 5: done. all: done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. congruence. - + eapply trees_equal_transfer_frozen_in_practice_many in HF' as [(Hfip&Hfip2)|(tr&Hdi9p&Hdip2)]. 3-5: eassumption. - * econstructor 6. all: edestruct Hfip2 as (px&Hpx&Hrz). 1: by eapply tree_equal_sym. - enough (px = Frozen) as -> by done. destruct Hrz as [->|(->&[=])]; tauto. - * econstructor 5; last done. all: eapply Hdip2. 2: done. 1: by eapply tree_equal_sym. - + econstructor 7. apply Hd'. - (* case 2: perm1 and perm2 are pseudo_conflicted Reserved *) - + econstructor 2. 1: done. 1: done. - eapply tree_equal_transfer_pseudo_conflicted. 5: exact HP2. all: done. - + econstructor 2; done. - + exfalso. done. - + econstructor 4. 2: done. - eapply conflicted_transfer_pseudo_disabled. - eapply tree_equal_transfer_pseudo_disabled. 4: done. all: done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor 5. 1: exact Hw1. 1: exact Hw3. simpl in *. eapply Hini'. - + eapply trees_equal_transfer_frozen_in_practice_many in HF' as [(Hfip&Hfip2)|(tr&Hdi9p&Hdip2)]. 3-5: eassumption. - * econstructor 6. all: edestruct Hfip2 as (px&Hpx&Hrz). 1: by eapply tree_equal_sym. - enough (px = Frozen) as -> by done. destruct Hrz as [->|(->&[=])]; tauto. - * econstructor 5; last done. all: eapply Hdip2. 2: done. 1: by eapply tree_equal_sym. - + inversion Hd'; simplify_eq. destruct confl1; last econstructor 1. - econstructor 7; econstructor; done. - (* case 3: perm1 and perm2 are unprotected reserved *) - + by econstructor 3. - + exfalso. done. - + by econstructor 3. - + econstructor 4. 2: done. - eapply conflicted_transfer_pseudo_disabled. - eapply tree_equal_transfer_pseudo_disabled. 4: done. all: done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + by econstructor 3. - + inversion Hd'; simplify_eq; done. - (* case 4: perm1 and perm2 are pseudo-disabled *) - + econstructor 4. 1: done. - eapply tree_equal_transfer_pseudo_disabled. 5: by eapply tree_equal_sym. all: done. - + econstructor 4. 1: done. - eapply conflicted_transfer_pseudo_disabled. - eapply tree_equal_transfer_pseudo_disabled. 5: by eapply tree_equal_sym. all: done. - + econstructor 4. 1: done. - eapply conflicted_transfer_pseudo_disabled. - eapply tree_equal_transfer_pseudo_disabled. 5: by eapply tree_equal_sym. all: done. - + econstructor 4. all: done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + econstructor 4. 1: done. - eapply conflicted_transfer_pseudo_disabled. - eapply tree_equal_transfer_pseudo_disabled. 5: by eapply tree_equal_sym. all: done. - + econstructor 4. 1: done. - eapply transfer_pseudo_disabled_notimm. - 1: eapply tree_equal_transfer_pseudo_disabled. 5: by eapply tree_equal_sym. 1-4: done. - all: inversion Hd'; done. - (* case 5: perm1 and perm2 are disabled in practice *) - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. congruence. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - (* case 6: perm1 and perm2 are frozen in practice. *) - + by econstructor 6. - + by econstructor 6. - + by econstructor 6. - + econstructor 4. 2: done. - eapply transfer_pseudo_disabled_notimm. - 1: eapply tree_equal_transfer_pseudo_disabled. 5: done. 1-4: done. - all: done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + by econstructor 6. - + inversion Hd'; try done. - simplify_eq. destruct confl1. 2: econstructor 1. - econstructor 7. econstructor. done. - (* case 7: the asymmetric case *) - + by econstructor 7. - + inversion Hd; simplify_eq. econstructor 2; try done. econstructor 1. - + inversion Hd; simplify_eq. done. - + econstructor 4. 2: done. - eapply transfer_pseudo_disabled_notimm. - 1: eapply tree_equal_transfer_pseudo_disabled. 5: done. 1-4: done. - all: by inversion Hd. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + eapply trees_equal_transfer_frozen_in_practice_many in HF' as [(Hfip&Hfip2)|(tr&Hdi9p&Hdip2)]. 3-5: eassumption. - * inversion Hd; simplify_eq. econstructor 6. - all: edestruct Hfip2 as (px&Hpx&Hrz). 1: by eapply tree_equal_sym. - enough (px = Frozen) as -> by done. destruct Hrz as [->|(->&[=])]; tauto. - * econstructor 5; last done. all: eapply Hdip2. 2: done. 1: by eapply tree_equal_sym. - + inversion Hd; inversion Hd'; by simplify_eq. - Qed. - - Lemma item_eq_up_to_C_trans {tr1 tr2 tr3 tg it1 it2 it3} : - protected_parents_not_disabled C tr2 → - (∀ tg, tree_contains tg tr1 → tree_unique tg tr1) → - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr1 → - parents_more_active tr2 → - no_active_cousins C tr1 → - no_active_cousins C tr2 → - tree_equal Forwards tr1 tr2 → - tree_equal Forwards tr2 tr3 → - item_eq_up_to_C tr1 tr2 tg Forwards it1 it2 → - item_eq_up_to_C tr2 tr3 tg Forwards it2 it3 → - item_eq_up_to_C tr1 tr3 tg Forwards it1 it3. - Proof. - intros Hnd ?????? He1 He2 H1 H2 l. - destruct (H1 l) as (H1l&H1r), (H2 l) as (H2l&H2r). - split; first congruence. - eapply perm_eq_up_to_C_trans. 1-9: done. - 1: exact H1r. rewrite H1l. 1: exact H2r. - Qed. - - - Lemma tree_equal_trans tr1 tr2 tr3 : - protected_parents_not_disabled C tr2 → - (∀ tg, tree_contains tg tr1 → tree_unique tg tr1) → - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr1 → - parents_more_active tr2 → - no_active_cousins C tr1 → - no_active_cousins C tr2 → - tree_equal Forwards tr1 tr2 → - tree_equal Forwards tr2 tr3 → - tree_equal Forwards tr1 tr3. - Proof. - rewrite /tree_equal. - intros ??????? [SameTg1 [SameRel1 EqC1]] [SameTg2 [SameRel2 EqC2]]. - split; [|split]. - + intro tg. rewrite SameTg1 SameTg2 //. - + intros tg tg'. rewrite SameRel1 SameRel2 //. - + intros tg Ex. - destruct (EqC1 _ Ex) as (it1M&it2M&Hlu1M&Hlu2M&Hiteq). - destruct (EqC2 tg) as (it1R&it2R&Hlu1R&Hlu2R&Hiteq2). - 1: by eapply Hlu2M. - assert (it2M = it1R) as -> by by eapply tree_lookup_unique. - exists it1M, it2R. split_and!; [done..|]. - eapply item_eq_up_to_C_trans; done. - Qed. - - Lemma trees_equal_trans trs1 trs2 trs3 : - each_tree_protected_parents_not_disabled C trs2 → - wf_trees trs1 → - wf_trees trs2 → - each_tree_parents_more_active trs1 → - each_tree_parents_more_active trs2 → - each_tree_no_active_cousins C trs1 → - each_tree_no_active_cousins C trs2 → - trees_equal Forwards trs1 trs2 → - trees_equal Forwards trs2 trs3 → - trees_equal Forwards trs1 trs3. - Proof. - rewrite /trees_equal. - intros Hu1 Hu2 Hu3 Hu4 Hu5 Hu6 Hu7 Equals1 Equals2 blk. - specialize (Equals1 blk). specialize (Equals2 blk). - destruct (trs1 !! blk) as [tr1|] eqn:Heq1; - destruct (trs2 !! blk) as [tr2|] eqn:Heq2; - destruct (trs3 !! blk) as [tr3|] eqn:Heq3. - all: inversion Equals1; inversion Equals2; simplify_eq; first [exfalso; congruence | econstructor]. - eapply tree_equal_trans. 8-9: eassumption. - 2: by eapply Hu2. 1: by eapply Hu1. 1: by eapply Hu3. 1: by eapply Hu4. 1: by eapply Hu5. 1: by eapply Hu6. 1: by eapply Hu7. - Qed. - -End utils. - -Section call_set. - - Lemma call_is_active_mono C1 C2 cid : - C1 ⊆ C2 → - call_is_active cid C1 → - call_is_active cid C2. - Proof. - rewrite /call_is_active. set_solver. - Qed. - - Lemma protector_is_active_mono C1 C2 prot : - C1 ⊆ C2 → - protector_is_active prot C1 → - protector_is_active prot C2. - Proof. - intros Hss (c&Hc1&Hc2). eexists; split; by eauto using call_is_active_mono. - Qed. - - Lemma pseudo_conflicted_mono C1 C2 tr tg off rc : - C1 ⊆ C2 → - pseudo_conflicted C1 tr tg off rc → - pseudo_conflicted C2 tr tg off rc. - Proof. - induction 2. - + econstructor 1. - + econstructor 2; by eauto using protector_is_active_mono. - Qed. - - Lemma protector_not_active_extend - {p c C} - (Hwf : ∀ c' : nat, protector_is_for_call c' p → (c' < c)%nat) - (NoProt : ¬ protector_is_active p C) - : ¬ protector_is_active p (C ∪ {[ c ]}). - Proof. - intros (cc&Hcc&[Hact|<-%elem_of_singleton]%elem_of_union). - 1: eapply NoProt; by eexists. - apply Hwf in Hcc. lia. - Qed. - - Lemma pseudo_disabled_mono C1 nxtc tr1 tg l p1 cid : - pseudo_disabled C1 tr1 tg l p1 cid → - pseudo_disabled (C1 ∪ {[ nxtc ]}) tr1 tg l p1 cid. - Proof. - induction 1 as [|???????? HH]. 1: by econstructor 1. - econstructor 2. 1,2,4: done. - 1: eapply protector_is_active_mono; last done; set_solver. - done. - Qed. - - Lemma is_disabled_mono C1 nxtc tr1 tg l p1 cid : - is_disabled C1 tr1 tg l p1 cid → - is_disabled (C1 ∪ {[ nxtc ]}) tr1 tg l p1 cid. - Proof. - induction 1 as [|]. 1: by econstructor 1. - econstructor 2. eapply pseudo_disabled_mono. done. - Qed. - - Lemma disabled_in_practice_mono C1 nxtc tr1 tg tg2 l: - disabled_in_practice C1 tr1 tg tg2 l → - disabled_in_practice (C1 ∪ {[ nxtc ]}) tr1 tg tg2 l. - Proof. - induction 1. econstructor. 1-2: done. - eapply is_disabled_mono. done. - Qed. - - Lemma perm_eq_up_to_C_mono (C1 : gset nat) (nxtc : nat) - tr1 tr2 tg l cid lp1 lp2 {d nxtp} : - (∀ cc, protector_is_for_call cc cid → (cc < nxtc)%nat) → - tree_items_compat_nexts tr1 nxtp nxtc → - tree_items_compat_nexts tr2 nxtp nxtc → - wf_tree tr1 → - wf_tree tr2 → - perm_eq_up_to_C C1 tr1 tr2 tg l cid d lp1 lp2 → - perm_eq_up_to_C (C1 ∪ {[ nxtc ]}) tr1 tr2 tg l cid d lp1 lp2. - Proof. - intros Hwf Hwf_all1 Hwf_all2 Hwf_tr1 Hwf_tr2. - induction 1 as [| |??? H|?? H1 H2|??? H1 H2 ?| |p1 p2 ini Hd]. - 1: by econstructor. - 1: econstructor; try done. 1: eapply protector_is_active_mono; last done; set_solver. - 1-2: eapply pseudo_conflicted_mono; last done; set_solver. - - econstructor 3; try done. - apply protector_not_active_extend; assumption. - - econstructor 4. all: eapply pseudo_disabled_mono; last done; done. - - econstructor 5; try done. - all: eapply disabled_in_practice_mono; last done. - - econstructor 6; done. - - econstructor 7. destruct d; inversion Hd as [x1 Hp|]; simplify_eq. - all: econstructor. - 2,4: eapply protector_is_active_mono; last done; set_solver. - all: eapply protector_not_active_extend; done. - Qed. - - Lemma loc_eq_up_to_C_mono C1 d tr1 tr2 tg it1 it2 nxtc nxtp l : - item_wf it1 nxtp nxtc → - tree_items_compat_nexts tr1 nxtp nxtc → - tree_items_compat_nexts tr2 nxtp nxtc → - wf_tree tr1 → - wf_tree tr2 → - loc_eq_up_to_C C1 tr1 tr2 tg d it1 it2 l → - loc_eq_up_to_C (C1 ∪ {[ nxtc ]}) tr1 tr2 tg d it1 it2 l. - Proof. - intros Hwf1 Hwf_all1 Hwf_all2 Hwf_tr1 Hwf_tr2. - induction 1; econstructor; try done. - eapply perm_eq_up_to_C_mono; last done. - 1: apply Hwf1. - all: eassumption. - Qed. - - Lemma item_eq_up_to_C_mono C1 d tr1 tr2 tg it1 it2 nxtc nxtp : - item_wf it1 nxtp nxtc → - tree_items_compat_nexts tr1 nxtp nxtc → - tree_items_compat_nexts tr2 nxtp nxtc → - wf_tree tr1 → - wf_tree tr2 → - item_eq_up_to_C C1 tr1 tr2 tg d it1 it2 → - item_eq_up_to_C (C1 ∪ {[ nxtc ]}) tr1 tr2 tg d it1 it2. - Proof. - intros Hss Hwf_all1 Hwf_all2 Hwf_tr1 Hwf_tr2 H1 l. - specialize (H1 l). by eapply loc_eq_up_to_C_mono. - Qed. - - Lemma tree_equal_mono C1 d tr1 tr2 nxtc nxtp : - tree_items_compat_nexts tr1 nxtp nxtc → - tree_items_compat_nexts tr2 nxtp nxtc → - wf_tree tr1 → - wf_tree tr2 → - tree_equal C1 d tr1 tr2 → - tree_equal (C1 ∪ {[ nxtc ]}) d tr1 tr2. - Proof. - intros Hss Hss2 Hwf_tr1 Hwf_tr2 (H1&H2&H3). do 2 (split; first done). - intros tg (it1&it2&H4&H5&H6)%H3. - exists it1, it2. split_and!; try done. - eapply item_eq_up_to_C_mono; try done. - setoid_rewrite every_node_eqv_universal in Hss. - apply Hss. eapply tree_lookup_to_exists_node. - erewrite <-tree_lookup_correct_tag in H4; done. - Qed. - - Lemma trees_equal_mono C1 d trs1 trs2 nxtc nxtp : - trees_compat_nexts trs1 nxtp nxtc → - trees_compat_nexts trs2 nxtp nxtc → - wf_trees trs1 → - wf_trees trs2 -> - trees_equal C1 d trs1 trs2 → - trees_equal (C1 ∪ {[ nxtc ]}) d trs1 trs2. - Proof. - intros Hss Hss2 Hwf_trs1 Hwf_trs2 Heq blk. specialize (Heq blk). inversion Heq; simplify_eq. - all: econstructor; try done. - eapply tree_equal_mono; try done. - + eapply Hss. done. - + eapply Hss2. done. - + eapply Hwf_trs1. done. - + eapply Hwf_trs2. done. - Qed. - -End call_set. - - diff --git a/theories/tree_borrows/trees_equal/trees_equal_asymmetric_prot.v b/theories/tree_borrows/trees_equal/trees_equal_asymmetric_prot.v index 5bf54797952e7fc155966aeeca2f4609ba542644..4c081cee9ea29cae84d8ad35909e3f13d5f2c98b 100644 --- a/theories/tree_borrows/trees_equal/trees_equal_asymmetric_prot.v +++ b/theories/tree_borrows/trees_equal/trees_equal_asymmetric_prot.v @@ -1,4 +1,3 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) From iris.proofmode Require Export proofmode. From iris.bi.lib Require Import fractional. From iris.base_logic.lib Require Import ghost_map. @@ -12,7 +11,6 @@ From simuliris.tree_borrows Require Import steps_progress. From simuliris.tree_borrows.trees_equal Require Import trees_equal_base random_lemmas. From iris.prelude Require Import options. -(* TODO cleanup *) Section utils. Context (C : call_id_set). @@ -304,4 +302,4 @@ Context (C : call_id_set). destruct (item_lookup it0 loc) as [ii pp]. simpl in *; subst ii pp. econstructor 1. Qed. -End utils. \ No newline at end of file +End utils. diff --git a/theories/tree_borrows/trees_equal/trees_equal_base.v b/theories/tree_borrows/trees_equal/trees_equal_base.v index 508e3a311bec21acd8c8d9131c60e2b603941b81..8c0500b124be830ac4cdacea099a18cd0f9b5ee2 100644 --- a/theories/tree_borrows/trees_equal/trees_equal_base.v +++ b/theories/tree_borrows/trees_equal/trees_equal_base.v @@ -1,4 +1,3 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) From iris.proofmode Require Export proofmode. From iris.bi.lib Require Import fractional. From iris.base_logic.lib Require Import ghost_map. @@ -12,8 +11,6 @@ From simuliris.tree_borrows Require Import steps_progress. From simuliris.tree_borrows Require Export trees_equal.disabled_in_practice. From iris.prelude Require Import options. - -(* TODO cleanup *) Section utils. Definition tag_valid (upper : tag) (n : tag) : Prop := (n < upper)%nat. @@ -151,7 +148,6 @@ Section utils. (* and define all the same relationships between those tags *) /\ (forall tg tg', rel_dec tr1 tg tg' = rel_dec tr2 tg tg') (* and have their permissions be equal up to C on all locations *) - (* FIXME: maybe think about reformulating ∧ (∀ t it1 it2, tree_lookup t it1 tr1 -> tree_lookup t it2 tr2 -> it_rel it1 it2) *) /\ (forall tg, tree_contains tg tr1 -> exists it1 it2, tree_lookup tr1 tg it1 diff --git a/theories/tree_borrows/trees_equal/trees_equal_create_child.v b/theories/tree_borrows/trees_equal/trees_equal_create_child.v index cd1d22fdcfe7eb410ebd5ec77ff01730b06b5db3..e9b0cb19f1bc003a73078ae1cd4fdca4bdffb7d2 100644 --- a/theories/tree_borrows/trees_equal/trees_equal_create_child.v +++ b/theories/tree_borrows/trees_equal/trees_equal_create_child.v @@ -1,4 +1,3 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) From iris.proofmode Require Export proofmode. From iris.bi.lib Require Import fractional. From iris.base_logic.lib Require Import ghost_map. @@ -12,7 +11,6 @@ From simuliris.tree_borrows Require Import steps_progress. From simuliris.tree_borrows.trees_equal Require Import trees_equal_base random_lemmas. From iris.prelude Require Import options. -(* TODO cleanup *) Section utils. Context (C : call_id_set). @@ -387,4 +385,4 @@ Context (C : call_id_set). Qed. -End utils. \ No newline at end of file +End utils. diff --git a/theories/tree_borrows/trees_equal/trees_equal_initcall.v b/theories/tree_borrows/trees_equal/trees_equal_initcall.v index 10c03dc2a07980a59bfd05ace6a18233c74f27e0..dbb1a8883e64b0edec994a08f1d8ac561a6bf9f8 100644 --- a/theories/tree_borrows/trees_equal/trees_equal_initcall.v +++ b/theories/tree_borrows/trees_equal/trees_equal_initcall.v @@ -1,4 +1,3 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) From iris.proofmode Require Export proofmode. From iris.bi.lib Require Import fractional. From iris.base_logic.lib Require Import ghost_map. diff --git a/theories/tree_borrows/trees_equal/trees_equal_more_access.v b/theories/tree_borrows/trees_equal/trees_equal_more_access.v index 747c550bee3bd50e8defb09e93a8feadcb78be63..c6382850a64bdd89baf2278335d4c907b355eff6 100644 --- a/theories/tree_borrows/trees_equal/trees_equal_more_access.v +++ b/theories/tree_borrows/trees_equal/trees_equal_more_access.v @@ -1,4 +1,3 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) From iris.proofmode Require Export proofmode. From iris.bi.lib Require Import fractional. From iris.base_logic.lib Require Import ghost_map. @@ -12,7 +11,6 @@ From simuliris.tree_borrows Require Import steps_progress. From simuliris.tree_borrows.trees_equal Require Import trees_equal_base random_lemmas. From iris.prelude Require Import options. -(* TODO cleanup *) Section utils. Context (C : call_id_set). @@ -79,11 +77,6 @@ Section utils. We now need to prove that actually there is also UB in the source, just not _here_, instead it occured at the cousin that creates the conflict. *) all: exfalso. - (* FIXME: here we need a lemma that shows - 1. a Child/This access for tg is Foreign for tg_cous who is Cousin of tg - 2. a Foreign access for such tg_cous is UB globally. - We can indeed check that in all of the following cases we have - rel = This or rel = Child and kind = AccessWrite. *) all: eapply cousin_write_for_initialized_protected_nondisabled_is_ub. all: try exact GlobalSuccess. all: try eassumption. diff --git a/theories/tree_borrows/trees_equal/trees_equal_preserved_by_access.v b/theories/tree_borrows/trees_equal/trees_equal_preserved_by_access.v index 0fd6ff7f10f7ddc03139a1983b49d977bb59a813..17f81ed1504a5cdc633a37573a81fa16d6881295 100644 --- a/theories/tree_borrows/trees_equal/trees_equal_preserved_by_access.v +++ b/theories/tree_borrows/trees_equal/trees_equal_preserved_by_access.v @@ -1,4 +1,3 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) From iris.proofmode Require Export proofmode. From iris.bi.lib Require Import fractional. From iris.base_logic.lib Require Import ghost_map. @@ -13,7 +12,6 @@ From simuliris.tree_borrows.trees_equal Require Import trees_equal_base random_l From simuliris.tree_borrows.trees_equal Require Export trees_equal_preserved_by_access_base. From iris.prelude Require Import options. -(* TODO cleanup *) Section utils. Context (C : call_id_set). diff --git a/theories/tree_borrows/trees_equal/trees_equal_preserved_by_access_base.v b/theories/tree_borrows/trees_equal/trees_equal_preserved_by_access_base.v index b40e646e177a081118228a1b02e905343af7158e..b0e6444ac195c68aa5e2388e026fb0e21db827f4 100644 --- a/theories/tree_borrows/trees_equal/trees_equal_preserved_by_access_base.v +++ b/theories/tree_borrows/trees_equal/trees_equal_preserved_by_access_base.v @@ -1,4 +1,3 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) From iris.proofmode Require Export proofmode. From iris.bi.lib Require Import fractional. From iris.base_logic.lib Require Import ghost_map. @@ -12,7 +11,6 @@ From simuliris.tree_borrows Require Import steps_progress. From simuliris.tree_borrows.trees_equal Require Import trees_equal_base random_lemmas. From iris.prelude Require Import options. -(* TODO cleanup *) Section utils. Context (C : call_id_set). diff --git a/theories/tree_borrows/trees_equal/trees_equal_source_read.v b/theories/tree_borrows/trees_equal/trees_equal_source_read.v index 0f0b65b17690aaf3b7c7900ffe1a3cc59ec97b91..902f3963a39d6c7d82c09ac2b1c1742a1f2ff956 100644 --- a/theories/tree_borrows/trees_equal/trees_equal_source_read.v +++ b/theories/tree_borrows/trees_equal/trees_equal_source_read.v @@ -1,4 +1,3 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) From iris.proofmode Require Export proofmode. From iris.bi.lib Require Import fractional. From iris.base_logic.lib Require Import ghost_map. @@ -12,7 +11,6 @@ From simuliris.tree_borrows Require Import steps_progress. From simuliris.tree_borrows.trees_equal Require Import trees_equal_base random_lemmas. From iris.prelude Require Import options. -(* TODO cleanup *) Section utils. Context (C : call_id_set). @@ -132,4 +130,4 @@ Context (C : call_id_set). destruct pp; try done. all: repeat (simpl in *; simplify_eq); by econstructor 1. Qed. -End utils. \ No newline at end of file +End utils. diff --git a/theories/tree_borrows/trees_equal/trees_equal_transitivity.v b/theories/tree_borrows/trees_equal/trees_equal_transitivity.v index 4906727bc23d759a663d21fafd4e80ad5665118c..9ebf91f1563912994ba5254b1856bdab590e27cc 100644 --- a/theories/tree_borrows/trees_equal/trees_equal_transitivity.v +++ b/theories/tree_borrows/trees_equal/trees_equal_transitivity.v @@ -1,4 +1,3 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) From iris.proofmode Require Export proofmode. From iris.bi.lib Require Import fractional. From iris.base_logic.lib Require Import ghost_map. @@ -12,7 +11,6 @@ From simuliris.tree_borrows Require Import steps_progress. From simuliris.tree_borrows.trees_equal Require Import trees_equal_base random_lemmas. From iris.prelude Require Import options. -(* TODO cleanup *) Section utils. Context (C : call_id_set). @@ -617,4 +615,4 @@ Context (C : call_id_set). Qed. -End utils. \ No newline at end of file +End utils. diff --git a/theories/tree_borrows/wf.v b/theories/tree_borrows/wf.v index f8e145f6d4c7bd13ca519b8c8ae51eb36b504ffd..2926d2d79985102823d08544bd9ae4588e029311 100755 --- a/theories/tree_borrows/wf.v +++ b/theories/tree_borrows/wf.v @@ -25,7 +25,7 @@ Section expr_wf. Fixpoint gen_expr_wf (e : expr) : Prop := expr_head_wf (expr_split_head e).1 ∧ match e with - (** [value_wf v] should be part of [expr_head_wf (Val v)] because + (** NOTE: [value_wf v] could be part of [expr_head_wf (Val v)] because [log_rel_structural] only provides [expr_head_wf]. *) | Val v => True | Var x => True @@ -44,7 +44,7 @@ Section expr_wf. | Case e branches => gen_expr_wf e ∧ Forall id (fmap gen_expr_wf branches) | While e1 e2 => gen_expr_wf e1 ∧ gen_expr_wf e2 | Fork e => gen_expr_wf e - (* These should have been handled by [expr_head_wf]. *) + (* NOTE: These could also have been handled by [expr_head_wf]. *) | EndCall e => gen_expr_wf e | InitCall => True (* administrative *) | Place _ _ _ => True (* literal pointers *) diff --git a/theories/tree_borrows/wishlist.v b/theories/tree_borrows/wishlist.v index e5ea6c2b6ddbf7fb540c3a917016c08e659466b3..2e59c69552f03b3cc7d2ae15ea0704331da9b7dc 100644 --- a/theories/tree_borrows/wishlist.v +++ b/theories/tree_borrows/wishlist.v @@ -1,14 +1,10 @@ +(** Reexports that are so universal that not including them here would make the + size of every other Require Import list explode. *) From iris.proofmode Require Export proofmode. From simuliris.tree_borrows Require Export tree_access_laws tag_protected_laws loc_controlled_laws. -From iris.base_logic.lib Require Import ghost_map. From simuliris.base_logic Require Export gen_sim_prog. From simuliris.simulation Require Export slsls. -From simuliris.simulation Require Import lifting. -From simuliris.tree_borrows Require Import tkmap_view. From simuliris.tree_borrows Require Export defs class_instances. -From simuliris.tree_borrows Require Import steps_progress steps_inv. -From simuliris.tree_borrows Require Import logical_state inv_accessors. -From simuliris.tree_borrows.trees_equal Require Import trees_equal_base random_lemmas. From iris.prelude Require Import options.