Theory Global_Invariants_Lemmas

(*<*)
(*
 * Copyright 2015, NICTA
 *
 * This software may be distributed and modified according to the terms of
 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
 * See "LICENSE_BSD2.txt" for details.
 *
 * @TAG(NICTA_BSD)
 *)

theory Global_Invariants_Lemmas
imports
  Global_Invariants
begin

declare subst_all [simp del] [[simproc del: defined_all]]

(*>*)
section‹Global invariants lemma bucket›

(* FIXME this file should be about the invs. This split makes it easier to move things around, maybe. *)

declare mut_m.mutator_phase_inv_aux.simps[simp]
case_of_simps mutator_phase_inv_aux_case: mut_m.mutator_phase_inv_aux.simps
case_of_simps sys_phase_inv_aux_case: sys_phase_inv_aux.simps


subsection‹TSO invariants›

lemma tso_store_inv_eq_imp:
  "eq_imp (λp s. mem_store_buffers (s sys) p)
          tso_store_inv"
by (simp add: eq_imp_def tso_store_inv_def)

lemmas tso_store_inv_fun_upd[simp] = eq_imp_fun_upd[OF tso_store_inv_eq_imp, simplified eq_imp_simps, rule_format]

lemma tso_store_invD[simp]:
  "tso_store_inv s ⟹ ¬sys_mem_store_buffers gc s = mw_Mutate r f r' # ws"
  "tso_store_inv s ⟹ ¬sys_mem_store_buffers gc s = mw_Mutate_Payload r f pl # ws"
  "tso_store_inv s ⟹ ¬sys_mem_store_buffers (mutator m) s = mw_fA fl # ws"
  "tso_store_inv s ⟹ ¬sys_mem_store_buffers (mutator m) s = mw_fM fl # ws"
  "tso_store_inv s ⟹ ¬sys_mem_store_buffers (mutator m) s = mw_Phase ph # ws"
by (auto simp: tso_store_inv_def dest!: spec[where x=m])

lemma mut_do_store_action[simp]:
  "⟦ sys_mem_store_buffers (mutator m) s = w # ws; tso_store_inv s ⟧ ⟹ fA (do_store_action w (s sys)) = sys_fA s"
  "⟦ sys_mem_store_buffers (mutator m) s = w # ws; tso_store_inv s ⟧ ⟹ fM (do_store_action w (s sys)) = sys_fM s"
  "⟦ sys_mem_store_buffers (mutator m) s = w # ws; tso_store_inv s ⟧ ⟹ phase (do_store_action w (s sys)) = sys_phase s"
by (auto simp: do_store_action_def split: mem_store_action.splits)

lemma tso_store_inv_sys_load_Mut[simp]:
  assumes "tso_store_inv s"
  assumes "(ract, v) ∈ { (mr_fM, mv_Mark (Some (sys_fM s))), (mr_fA, mv_Mark (Some (sys_fA s))), (mr_Phase, mv_Phase (sys_phase s)) }"
  shows "sys_load (mutator m) ract (s sys) = v"
using assms
apply (clarsimp simp: sys_load_def fold_stores_def)
apply (rule fold_invariant[where P="λfr. do_load_action ract (fr (s sys)) = v" and Q="mut_writes"])
  apply (fastforce simp: tso_store_inv_def)
 apply (auto simp: do_load_action_def split: mem_store_action.splits)
done

lemma tso_store_inv_sys_load_GC[simp]:
  assumes "tso_store_inv s"
  shows "sys_load gc (mr_Ref r f) (s sys) = mv_Ref (Option.bind (sys_heap s r) (λobj. obj_fields obj f))" (is "?lhs = mv_Ref ?rhs")
using assms unfolding sys_load_def fold_stores_def
apply clarsimp
apply (rule fold_invariant[where P="λfr. Option.bind (heap (fr (s sys)) r) (λobj. obj_fields obj f) = ?rhs"
                             and Q="λw. ∀r f r'. w ≠ mw_Mutate r f r'"])
  apply (fastforce simp: tso_store_inv_def)
 apply (auto simp: do_store_action_def map_option_case fun_upd_apply
            split: mem_store_action.splits option.splits)
done

lemma tso_no_pending_marksD[simp]:
  assumes "tso_pending_mark p s = []"
  shows "sys_load p (mr_Mark r) (s sys) = mv_Mark (map_option obj_mark (sys_heap s r))"
using assms unfolding sys_load_def fold_stores_def
apply clarsimp
apply (rule fold_invariant[where P="λfr. map_option obj_mark (heap (fr (s sys)) r) = map_option obj_mark (sys_heap s r)"
                             and Q="λw. ∀fl. w ≠ mw_Mark r fl"])
  apply (auto simp: map_option_case do_store_action_def filter_empty_conv fun_upd_apply
             split: mem_store_action.splits option.splits)
done

lemma no_pending_phase_sys_load[simp]:
  assumes "tso_pending_phase p s = []"
  shows "sys_load p mr_Phase (s sys) = mv_Phase (sys_phase s)"
using assms
apply (clarsimp simp: sys_load_def fold_stores_def)
apply (rule fold_invariant[where P="λfr. phase (fr (s sys)) = sys_phase s" and Q="λw. ∀ph. w ≠ mw_Phase ph"])
  apply (auto simp: do_store_action_def filter_empty_conv
             split: mem_store_action.splits)
done

lemma gc_no_pending_fM_write[simp]:
  assumes "tso_pending_fM gc s = []"
  shows "sys_load gc mr_fM (s sys) = mv_Mark (Some (sys_fM s))"
using assms
apply (clarsimp simp: sys_load_def fold_stores_def)
apply (rule fold_invariant[where P="λfr. fM (fr (s sys)) = sys_fM s" and Q="λw. ∀fl. w ≠ mw_fM fl"])
  apply (auto simp: do_store_action_def filter_empty_conv
             split: mem_store_action.splits)
done

lemma tso_store_refs_simps[simp]:
  "mut_m.tso_store_refs m (s(mutator m' := s (mutator m')⦇roots := roots'⦈))
 = mut_m.tso_store_refs m s"
  "mut_m.tso_store_refs m (s(mutator m' := s (mutator m')⦇ghost_honorary_root := {}⦈,
                             sys := s sys⦇mem_store_buffers := (mem_store_buffers (s sys))(mutator m' := sys_mem_store_buffers (mutator m') s @ [mw_Mutate r f opt_r'])⦈))
 = mut_m.tso_store_refs m s ∪ (if m' = m then store_refs (mw_Mutate r f opt_r') else {})"
  "mut_m.tso_store_refs m (s(sys := s sys⦇mem_store_buffers := (mem_store_buffers (s sys))(mutator m' := sys_mem_store_buffers (mutator m') s @ [mw_Mutate_Payload r f pl])⦈))
 = mut_m.tso_store_refs m s ∪ (if m' = m then store_refs (mw_Mutate_Payload r f pl) else {})"
  "mut_m.tso_store_refs m (s(sys := s sys⦇heap := (sys_heap s)(r' := None)⦈))
 = mut_m.tso_store_refs m s"
  "mut_m.tso_store_refs m (s(mutator m' := s (mutator m')⦇roots := insert r (roots (s (mutator m')))⦈, sys := s sys⦇heap := (sys_heap s)(r ↦ obj)⦈))
 = mut_m.tso_store_refs m s"
  "mut_m.tso_store_refs m (s(mutator m' := s (mutator m')⦇ghost_honorary_root := Option.set_option opt_r', ref := opt_r'⦈))
 = mut_m.tso_store_refs m s"
  "mut_m.tso_store_refs m (s(sys := s sys⦇heap := (sys_heap s)(r := map_option (λobj. obj⦇obj_fields := (obj_fields obj)(f := opt_r')⦈) (sys_heap s r)),
                                          mem_store_buffers := (mem_store_buffers (s sys))(p := ws)⦈))
 = (if p = mutator m then ⋃w ∈ set ws. store_refs w else mut_m.tso_store_refs m s)"
  "mut_m.tso_store_refs m (s(sys := s sys⦇heap := (sys_heap s)(r := map_option (λobj. obj⦇obj_payload := (obj_payload obj)(f := pl)⦈) (sys_heap s r)),
                                          mem_store_buffers := (mem_store_buffers (s sys))(p := ws)⦈))
 = (if p = mutator m then ⋃w ∈ set ws. store_refs w else mut_m.tso_store_refs m s)"
  "sys_mem_store_buffers p s = mw_Mark r fl # ws
⟹ mut_m.tso_store_refs m (s(sys := s sys⦇heap := (sys_heap s)(r := map_option (obj_mark_update (λ_. fl)) (sys_heap s r)), mem_store_buffers := (mem_store_buffers (s sys))(p := ws)⦈))
 = mut_m.tso_store_refs m s"
unfolding mut_m.tso_store_refs_def by (auto simp: fun_upd_apply)

lemma fold_stores_points_to[rule_format, simplified conj_explode]:
  "heap (fold_stores ws (s sys)) r = Some obj ∧ obj_fields obj f = Some r'
     ⟶ (r points_to r') s ∨ (∃w ∈ set ws. r' ∈ store_refs w)" (is "?P (fold_stores ws) obj")
unfolding fold_stores_def
apply (rule spec[OF fold_invariant[where P="λfr. ∀obj. ?P fr obj" and Q="λw. w ∈ set ws"]])
  apply fastforce
 apply (fastforce simp: ran_def split: obj_at_splits)
apply clarsimp
apply (drule (1) bspec)
apply (clarsimp simp: fun_upd_apply split: mem_store_action.split_asm if_splits)
done

lemma points_to_Mutate:
  "(x points_to y)
         (s(sys := (s sys)⦇ heap := (sys_heap s)(r := map_option (λobj. obj⦇obj_fields := (obj_fields obj)(f := opt_r')⦈) (sys_heap s r)),
                            mem_store_buffers := (mem_store_buffers (s sys))(p := ws) ⦈))
  ⟷ (r ≠ x ∧ (x points_to y) s) ∨ (r = x ∧ valid_ref r s ∧ (opt_r' = Some y ∨ ( (x points_to y) s ∧ obj_at (λobj. ∃f'. obj_fields obj f' = Some y ∧ f ≠ f') r s)))"
unfolding ran_def by (auto simp: fun_upd_apply split: obj_at_splits)


subsection‹ FIXME mutator handshake facts ›

lemma ― ‹Sanity›
  "hp' = hs_step hp ⟹ ∃in' ht. (in', ht, hp', hp) ∈ hp_step_rel"
by (cases hp) (auto simp: hp_step_rel_def)

lemma ― ‹Sanity›
  "(False, ht, hp', hp) ∈ hp_step_rel ⟹ hp' = hp_step ht hp"
by (cases ht) (auto simp: hp_step_rel_def)

lemma (in mut_m) handshake_phase_invD:
  assumes "handshake_phase_inv s"
  shows "(sys_ghost_hs_in_sync m s, sys_hs_type s, sys_ghost_hs_phase s, mut_ghost_hs_phase s) ∈ hp_step_rel
       ∧ (sys_hs_pending m s ⟶ ¬sys_ghost_hs_in_sync m s)"
using assms unfolding handshake_phase_inv_def by simp

lemma handshake_in_syncD:
  "⟦ All (ghost_hs_in_sync (s sys)); handshake_phase_inv s ⟧
     ⟹ ∀m'. mut_m.mut_ghost_hs_phase m' s = sys_ghost_hs_phase s"
by clarsimp (auto simp: hp_step_rel_def dest!: mut_m.handshake_phase_invD)

lemmas fM_rel_invD = iffD1[OF fun_cong[OF fM_rel_inv_def[simplified atomize_eq]]]

text‹

Relate @{const "sys_ghost_hs_phase"}, @{const "gc_phase"},
@{const "sys_phase"} and writes to the phase in the GC's TSO buffer.

›

simps_of_case handshake_phase_rel_simps[simp]: handshake_phase_rel_def (splits: hs_phase.split)

lemma phase_rel_invD:
  assumes "phase_rel_inv s"
  shows "(∀m. sys_ghost_hs_in_sync m s, sys_ghost_hs_phase s, gc_phase s, sys_phase s, tso_pending_phase gc s) ∈ phase_rel"
using assms unfolding phase_rel_inv_def by simp

lemma mut_m_not_idle_no_fM_write:
  "⟦ ghost_hs_phase (s (mutator m)) ≠ hp_Idle; fM_rel_inv s; handshake_phase_inv s; tso_store_inv s; p ≠ sys ⟧
     ⟹ ¬sys_mem_store_buffers p s = mw_fM fl # ws"
apply (drule mut_m.handshake_phase_invD[where m=m])
apply (drule fM_rel_invD)
apply (clarsimp simp: hp_step_rel_def fM_rel_def filter_empty_conv p_not_sys)
apply (metis list.set_intros(1) tso_store_invD(4))
done

lemma (in mut_m) mut_ghost_handshake_phase_idle:
  "⟦ mut_ghost_hs_phase s = hp_Idle; handshake_phase_inv s; phase_rel_inv s ⟧
     ⟹ sys_phase s = ph_Idle"
apply (drule phase_rel_invD)
apply (drule handshake_phase_invD)
apply (auto simp: phase_rel_def hp_step_rel_def)
done

lemma mut_m_not_idle_no_fM_writeD:
  "⟦ sys_mem_store_buffers p s = mw_fM fl # ws; ghost_hs_phase (s (mutator m)) ≠ hp_Idle; fM_rel_inv s; handshake_phase_inv s; tso_store_inv s; p ≠ sys ⟧
     ⟹ False"
apply (drule mut_m.handshake_phase_invD[where m=m])
apply (drule fM_rel_invD)
apply (clarsimp simp: hp_step_rel_def fM_rel_def filter_empty_conv p_not_sys)
apply (metis list.set_intros(1) tso_store_invD(4))
done


subsection‹points to, reaches, reachable mut›

lemma (in mut_m) reachable_eq_imp:
  "eq_imp (λr'. mut_roots ⊗ mut_ghost_honorary_root ⊗ (λs. ⋃(ran ` obj_fields ` set_option (sys_heap s r')))
              ⊗ tso_pending_mutate (mutator m))
          (reachable r)"
unfolding eq_imp_def reachable_def tso_store_refs_def
apply clarsimp
apply (rename_tac s s')
apply (subgoal_tac "∀r'. (∃w∈set (sys_mem_store_buffers (mutator m) s). r' ∈ store_refs w) ⟷ (∃w∈set (sys_mem_store_buffers (mutator m) s'). r' ∈ store_refs w)")
 apply (subgoal_tac "∀x. (x reaches r) s ⟷ (x reaches r) s'")
  apply (clarsimp; fail)
 apply (auto simp: reaches_fields; fail)[1]
apply (drule arg_cong[where f=set])
apply (clarsimp simp: set_eq_iff)
apply (rule iffI)
 apply clarsimp
 apply (rename_tac s s' r' w)
 apply (drule_tac x=w in spec)
 apply (rule_tac x=w in bexI)
  apply (clarsimp; fail)
 apply (clarsimp split: mem_store_action.splits; fail)
apply clarsimp
apply (rename_tac s s' r' w)
apply (drule_tac x=w in spec)
apply (rule_tac x=w in bexI)
 apply (clarsimp; fail)
apply (clarsimp split: mem_store_action.splits; fail)
done

lemmas reachable_fun_upd[simp] = eq_imp_fun_upd[OF mut_m.reachable_eq_imp, simplified eq_imp_simps, rule_format]

lemma reachableI[intro]:
  "x ∈ mut_m.mut_roots m s ⟹ mut_m.reachable m x s"
  "x ∈ mut_m.tso_store_refs m s ⟹ mut_m.reachable m x s"
by (auto simp: mut_m.reachable_def reaches_def)

lemma reachable_points_to[elim]:
  "⟦ (x points_to y) s; mut_m.reachable m x s ⟧ ⟹ mut_m.reachable m y s"
by (auto simp: mut_m.reachable_def reaches_def elim: rtranclp.intros(2))

lemma (in mut_m) mut_reachableE[consumes 1, case_names mut_root tso_store_refs]:
  "⟦ reachable y s;
     ⋀x. ⟦ (x reaches y) s; x ∈ mut_roots s ⟧ ⟹ Q;
     ⋀x. ⟦ (x reaches y) s; x ∈ mut_ghost_honorary_root s ⟧ ⟹ Q;
     ⋀x. ⟦ (x reaches y) s; x ∈ tso_store_refs s ⟧ ⟹ Q ⟧ ⟹ Q"
by (auto simp: reachable_def)

lemma reachable_induct[consumes 1, case_names root ghost_honorary_root tso_root reaches]:
  assumes r: "mut_m.reachable m y s"
  assumes root: "⋀x. ⟦ x ∈ mut_m.mut_roots m s ⟧ ⟹ P x"
  assumes ghost_honorary_root: "⋀x. ⟦ x ∈ mut_m.mut_ghost_honorary_root m s ⟧ ⟹ P x"
  assumes tso_root: "⋀x. x ∈ mut_m.tso_store_refs m s ⟹ P x"
  assumes reaches: "⋀x y. ⟦ mut_m.reachable m x s; (x points_to y) s; P x ⟧ ⟹ P y"
  shows "P y"
using r unfolding mut_m.reachable_def
proof(clarify)
  fix x
  assume "(x reaches y) s" and "x ∈ mut_m.mut_roots m s ∪ mut_m.mut_ghost_honorary_root m s ∪ mut_m.tso_store_refs m s"
  then show "P y"
  unfolding reaches_def proof induct
    case base with root ghost_honorary_root tso_root show ?case by blast
  next
    case (step y z) with reaches show ?case
      unfolding mut_m.reachable_def reaches_def by meson
  qed
qed

lemma mutator_reachable_tso:
  "sys_mem_store_buffers (mutator m) s = mw_Mutate r f opt_r' # ws
    ⟹ mut_m.reachable m r s ∧ (∀r'. opt_r' = Some r' ⟶ mut_m.reachable m r' s)"
  "sys_mem_store_buffers (mutator m) s = mw_Mutate_Payload r f pl # ws
    ⟹ mut_m.reachable m r s"
by (auto simp: mut_m.tso_store_refs_def)


subsection‹ Colours ›

lemma greyI[intro]:
  "r ∈ ghost_honorary_grey (s p) ⟹ grey r s"
  "r ∈ W (s p) ⟹ grey r s"
  "r ∈ WL p s ⟹ grey r s"
unfolding grey_def WL_def by (case_tac [!] p) auto

lemma blackD[dest]:
  "black r s ⟹ marked r s"
  "black r s ⟹ r ∉ WL p s"
unfolding black_def grey_def by simp_all

lemma whiteI[intro]: (* FIXME simp normal form of def *)
  "obj_at (λobj. obj_mark obj = (¬ sys_fM s)) r s ⟹ white r s"
unfolding white_def by simp

lemma marked_not_white[dest]:
  "white r s ⟹ ¬marked r s"
unfolding white_def by (simp_all split: obj_at_splits)

lemma white_valid_ref[elim!]:
  "white r s ⟹ valid_ref r s"
unfolding white_def by (simp_all split: obj_at_splits)

lemma not_white_marked[elim!]:
  "⟦¬ white r s; valid_ref r s⟧ ⟹ marked r s"
unfolding white_def by (simp split: obj_at_splits)

lemma black_eq_imp:
  "eq_imp (λ_::unit. (λs. r ∈ (⋃p. WL p s)) ⊗ sys_fM ⊗ (λs. map_option obj_mark (sys_heap s r)))
          (black r)"
unfolding eq_imp_def black_def grey_def by (auto split: obj_at_splits)

lemma grey_eq_imp:
  "eq_imp (λ_::unit. (λs. r ∈ (⋃p. WL p s)))
          (grey r)"
unfolding eq_imp_def grey_def by auto

lemma white_eq_imp:
  "eq_imp (λ_::unit. sys_fM ⊗ (λs. map_option obj_mark (sys_heap s r)))
          (white r)"
unfolding eq_imp_def white_def by (auto split: obj_at_splits)

lemmas black_fun_upd[simp] = eq_imp_fun_upd[OF black_eq_imp, simplified eq_imp_simps, rule_format]
lemmas grey_fun_upd[simp] = eq_imp_fun_upd[OF grey_eq_imp, simplified eq_imp_simps, rule_format]
lemmas white_fun_upd[simp] = eq_imp_fun_upd[OF white_eq_imp, simplified eq_imp_simps, rule_format]


text‹coloured heaps›

lemma black_heap_eq_imp:
  "eq_imp (λr'. (λs. ⋃p. WL p s) ⊗ sys_fM ⊗ (λs. map_option obj_mark (sys_heap s r')))
          black_heap"
apply (clarsimp simp: eq_imp_def black_heap_def black_def grey_def all_conj_distrib fun_eq_iff split: option.splits)
apply (rename_tac s s')
apply (subgoal_tac "∀x. marked x s ⟷ marked x s'")
 apply (subgoal_tac "∀x. valid_ref x s ⟷ valid_ref x s'")
  apply (subgoal_tac "∀x. (∀p. x ∉ WL p s) ⟷ (∀p. x ∉ WL p s')")
   apply clarsimp
  apply (auto simp: set_eq_iff)[1]
 apply clarsimp
 apply (rename_tac x)
 apply (rule eq_impD[OF obj_at_eq_imp])
 apply (drule_tac x=x in spec)
 apply (drule_tac f="map_option ⟨True⟩" in arg_cong)
 apply fastforce
apply clarsimp
apply (rule eq_impD[OF obj_at_eq_imp])
apply clarsimp
apply (rename_tac x)
apply (drule_tac x=x in spec)
apply (drule_tac f="map_option (λfl. fl = sys_fM s)" in arg_cong)
apply simp
done

lemma white_heap_eq_imp:
  "eq_imp (λr'. sys_fM ⊗ (λs. map_option obj_mark (sys_heap s r')))
          white_heap"
apply (clarsimp simp: all_conj_distrib eq_imp_def white_def white_heap_def obj_at_def fun_eq_iff
               split: option.splits)
apply (rule iffI)
apply (metis (opaque_lifting, no_types) map_option_eq_Some)+
done

lemma no_black_refs_eq_imp:
  "eq_imp (λr'. (λs. (⋃p. WL p s)) ⊗ sys_fM ⊗ (λs. map_option obj_mark (sys_heap s r')))
          no_black_refs"
apply (clarsimp simp add: eq_imp_def no_black_refs_def black_def grey_def all_conj_distrib fun_eq_iff set_eq_iff split: option.splits)
apply (rename_tac s s')
apply (subgoal_tac "∀x. marked x s ⟷ marked x s'")
 apply clarsimp
apply (clarsimp split: obj_at_splits)
apply (rename_tac x)
apply (drule_tac x=x in spec)+
apply (auto split: obj_at_splits)
done

lemmas black_heap_fun_upd[simp] = eq_imp_fun_upd[OF black_heap_eq_imp, simplified eq_imp_simps, rule_format]
lemmas white_heap_fun_upd[simp] = eq_imp_fun_upd[OF white_heap_eq_imp, simplified eq_imp_simps, rule_format]
lemmas no_black_refs_fun_upd[simp] = eq_imp_fun_upd[OF no_black_refs_eq_imp, simplified eq_imp_simps, rule_format]

lemma white_heap_imp_no_black_refs[elim!]:
  "white_heap s ⟹ no_black_refs s"
apply (clarsimp simp: white_def white_heap_def no_black_refs_def black_def)
apply (rename_tac x)
apply (drule_tac x=x in spec)
apply (clarsimp split: obj_at_splits)
done

lemma black_heap_no_greys[elim]:
  "⟦ no_grey_refs s; ∀r. marked r s ∨ ¬valid_ref r s ⟧ ⟹ black_heap s"
unfolding black_def black_heap_def no_grey_refs_def by fastforce

lemma heap_colours_colours:
  "black_heap s ⟹ ¬white r s"
  "white_heap s ⟹ ¬black r s"
by (auto simp: black_heap_def white_def white_heap_def
        dest!: spec[where x=r]
        split: obj_at_splits)


text‹The strong-tricolour invariant ›

lemma strong_tricolour_invD:
  "⟦ black x s; (x points_to y) s; valid_ref y s; strong_tricolour_inv s ⟧
     ⟹ marked y s"
unfolding strong_tricolour_inv_def by fastforce

lemma no_black_refsD:
  "no_black_refs s ⟹ ¬black r s"
unfolding no_black_refs_def by simp

lemma has_white_path_to_induct[consumes 1, case_names refl step, induct set: has_white_path_to]:
  assumes "(x has_white_path_to y) s"
  assumes "⋀x. P x x"
  assumes "⋀x y z. ⟦(x has_white_path_to y) s; P x y; (y points_to z) s; white z s⟧ ⟹ P x z"
  shows "P x y"
using assms unfolding has_white_path_to_def by (rule rtranclp.induct; blast)

lemma has_white_path_toD[dest]:
  "(x has_white_path_to y) s ⟹ white y s ∨ x = y"
unfolding has_white_path_to_def by (fastforce elim: rtranclp.cases)

lemma has_white_path_to_refl[iff]:
  "(x has_white_path_to x) s"
unfolding has_white_path_to_def by simp

lemma has_white_path_to_step[intro]:
  "⟦(x has_white_path_to y) s; (y points_to z) s; white z s⟧ ⟹ (x has_white_path_to z) s"
  "⟦(y has_white_path_to z) s; (x points_to y) s; white y s⟧ ⟹ (x has_white_path_to z) s"
unfolding has_white_path_to_def
 apply (simp add: rtranclp.rtrancl_into_rtrancl)
apply (simp add: converse_rtranclp_into_rtranclp)
done

lemma has_white_path_toE[elim!]:
  "⟦ (x points_to y) s; white y s ⟧ ⟹ (x has_white_path_to y) s"
unfolding has_white_path_to_def by (auto elim: rtranclp.intros(2))

lemma has_white_path_to_reaches[elim]:
  "(x has_white_path_to y) s ⟹ (x reaches y) s"
unfolding has_white_path_to_def reaches_def
by (induct rule: rtranclp.induct) (auto intro: rtranclp.intros(2))

lemma has_white_path_to_blacken[simp]:
  "(x has_white_path_to w) (s(gc := s gc⦇ W := gc_W s - rs ⦈)) ⟷ (x has_white_path_to w) s"
unfolding has_white_path_to_def by (simp add: fun_upd_apply)

lemma has_white_path_to_eq_imp': ― ‹Complicated condition takes care of ‹alloc›: collapses no object and object with no fields›
  assumes "(x has_white_path_to y) s'"
  assumes "∀r'. ⋃(ran ` obj_fields ` set_option (sys_heap s' r')) = ⋃(ran ` obj_fields ` set_option (sys_heap s r'))"
  assumes "∀r'. map_option obj_mark (sys_heap s' r') = map_option obj_mark (sys_heap s r')"
  assumes "sys_fM s' = sys_fM s"
  shows "(x has_white_path_to y) s"
using assms
proof induct
  case (step x y z)
  then have "(y points_to z) s"
    by (cases "sys_heap s y")
       (auto 10 10 simp: ran_def obj_at_def split: option.splits dest!: spec[where x=y])
  with step show ?case
apply -
apply (rule has_white_path_to_step, assumption, assumption)
apply (clarsimp simp: white_def split: obj_at_splits)
apply (metis map_option_eq_Some option.sel)
done
qed simp

lemma has_white_path_to_eq_imp:
  "eq_imp (λr'. sys_fM ⊗ (λs. ⋃(ran ` obj_fields ` set_option (sys_heap s r'))) ⊗ (λs. map_option obj_mark (sys_heap s r')))
          (x has_white_path_to y)"
unfolding eq_imp_def
apply (clarsimp simp: all_conj_distrib)
apply (rule iffI)
 apply (erule has_white_path_to_eq_imp'; auto)
apply (erule has_white_path_to_eq_imp'; auto)
done

lemmas has_white_path_to_fun_upd[simp] = eq_imp_fun_upd[OF has_white_path_to_eq_imp, simplified eq_imp_simps, rule_format]


text‹grey protects white›

lemma grey_protects_whiteD[dest]:
  "(g grey_protects_white w) s ⟹ grey g s ∧ (g = w ∨ white w s)"
by (auto simp: grey_protects_white_def)

lemma grey_protects_whiteI[iff]:
  "grey g s ⟹ (g grey_protects_white g) s"
by (simp add: grey_protects_white_def)

lemma grey_protects_whiteE[elim!]:
  "⟦ (g points_to w) s; grey g s; white w s ⟧ ⟹ (g grey_protects_white w) s"
  "⟦ (g grey_protects_white y) s; (y points_to w) s; white w s ⟧ ⟹ (g grey_protects_white w) s"
by (auto simp: grey_protects_white_def)

lemma grey_protects_white_reaches[elim]:
  "(g grey_protects_white w) s ⟹ (g reaches w) s"
by (auto simp: grey_protects_white_def)

lemma grey_protects_white_induct[consumes 1, case_names refl step, induct set: grey_protects_white]:
  assumes "(g grey_protects_white w) s"
  assumes "⋀x. grey x s ⟹ P x x"
  assumes "⋀x y z. ⟦(x has_white_path_to y) s; P x y; (y points_to z) s; white z s⟧ ⟹ P x z"
  shows "P g w"
using assms unfolding grey_protects_white_def
apply -
apply (elim conjE)
apply (rotate_tac -1)
apply (induct rule: has_white_path_to_induct)
apply blast+
done


subsection‹ @{term "valid_W_inv"} ›

lemma valid_W_inv_sys_ghg_empty_iff[elim!]:
  "valid_W_inv s ⟹ sys_ghost_honorary_grey s = {}"
unfolding valid_W_inv_def by simp

lemma WLI[intro]:
  "r ∈ W (s p) ⟹ r ∈ WL p s"
  "r ∈ ghost_honorary_grey (s p) ⟹ r ∈ WL p s"
unfolding WL_def by simp_all

lemma WL_eq_imp:
  "eq_imp (λ(_::unit) s. (ghost_honorary_grey (s p), W (s p)))
          (WL p)"
unfolding eq_imp_def WL_def by simp

lemmas WL_fun_upd[simp] = eq_imp_fun_upd[OF WL_eq_imp, simplified eq_imp_simps, rule_format]

lemma valid_W_inv_eq_imp:
  "eq_imp (λ(p, r). (λs. W (s p)) ⊗ (λs. ghost_honorary_grey (s p)) ⊗ sys_fM ⊗ (λs. map_option obj_mark (sys_heap s r)) ⊗ sys_mem_lock ⊗ tso_pending_mark p)
          valid_W_inv"
apply (clarsimp simp: eq_imp_def valid_W_inv_def fun_eq_iff all_conj_distrib white_def)
apply (rename_tac s s')
apply (subgoal_tac "∀p. WL p s = WL p s'")
 apply (subgoal_tac "∀x. marked x s ⟷ marked x s'")
  apply (subgoal_tac "∀x. obj_at (λobj. obj_mark obj = (¬sys_fM s')) x s ⟷ obj_at (λobj. obj_mark obj = (¬sys_fM s')) x s'")
   apply (subgoal_tac "∀x xa xb. mw_Mark xa xb ∈ set (sys_mem_store_buffers x s) ⟷ mw_Mark xa xb ∈ set (sys_mem_store_buffers x s')")
    apply (simp; fail)
   apply clarsimp
   apply (rename_tac x xa xb)
   apply (drule_tac x=x in spec, drule arg_cong[where f=set], fastforce)
  apply (clarsimp split: obj_at_splits)
  apply (rename_tac x)
  apply ( (drule_tac x=x in spec)+ )[1]
  apply (case_tac "sys_heap s x", simp_all)
   apply (case_tac "sys_heap s' x", auto)[1]
 apply (clarsimp split: obj_at_splits)
 apply (rename_tac x)
 apply (drule_tac x=x in spec)
 apply (case_tac "sys_heap s x", simp_all)
 apply (case_tac "sys_heap s' x", simp_all)
apply (simp add: WL_def)
done

lemmas valid_W_inv_fun_upd[simp] = eq_imp_fun_upd[OF valid_W_inv_eq_imp, simplified eq_imp_simps, rule_format]

lemma valid_W_invE[elim!]:
  "⟦ r ∈ W (s p); valid_W_inv s ⟧ ⟹ marked r s"
  "⟦ r ∈ ghost_honorary_grey (s p); sys_mem_lock s ≠ Some p; valid_W_inv s ⟧ ⟹ marked r s"
  "⟦ r ∈ W (s p); valid_W_inv s ⟧ ⟹ valid_ref r s"
  "⟦ r ∈ ghost_honorary_grey (s p); sys_mem_lock s ≠ Some p; valid_W_inv s ⟧ ⟹ valid_ref r s"
  "⟦ mw_Mark r fl ∈ set (sys_mem_store_buffers p s); valid_W_inv s ⟧ ⟹ r ∈ ghost_honorary_grey (s p)"
unfolding valid_W_inv_def
apply (simp_all add:  split: obj_at_splits)
apply blast+
done

lemma valid_W_invD:
  "⟦ sys_mem_store_buffers p s = mw_Mark r fl # ws; valid_W_inv s ⟧
     ⟹ fl = sys_fM s ∧ r ∈ ghost_honorary_grey (s p) ∧ tso_locked_by p s ∧ white r s ∧ filter is_mw_Mark ws = []"
  "⟦ mw_Mark r fl ∈ set (sys_mem_store_buffers p s); valid_W_inv s ⟧
     ⟹ fl = sys_fM s ∧ r ∈ ghost_honorary_grey (s p) ∧ tso_locked_by p s ∧ white r s ∧ filter is_mw_Mark (sys_mem_store_buffers p s) = [mw_Mark r fl]"
unfolding valid_W_inv_def white_def by (clarsimp dest!: spec[where x=p], blast)+

lemma valid_W_inv_colours:
  "⟦white x s; valid_W_inv s⟧ ⟹ x ∉ W (s p)"
using marked_not_white valid_W_invE(1) by force

lemma valid_W_inv_no_mark_stores_invD:
  "⟦ sys_mem_lock s ≠ Some p; valid_W_inv s ⟧
     ⟹ tso_pending p is_mw_Mark s = []"
by (auto dest: valid_W_invD(2) intro!: filter_False)

lemma valid_W_inv_sys_load[simp]:
  "⟦ sys_mem_lock s ≠ Some p; valid_W_inv s ⟧
     ⟹ sys_load p (mr_Mark r) (s sys) = mv_Mark (map_option obj_mark (sys_heap s r))"
unfolding sys_load_def fold_stores_def
apply clarsimp
apply (rule fold_invariant[where P="λfr. map_option obj_mark (heap (fr (s sys)) r) = map_option obj_mark (sys_heap s r)"
                             and Q="λw. ∀r fl. w ≠ mw_Mark r fl"])
  apply (auto simp: map_option_case do_store_action_def filter_empty_conv fun_upd_apply
              dest: valid_W_invD(2)
             split: mem_store_action.splits option.splits)
done


subsection‹ ‹grey_reachable› ›

lemma grey_reachable_eq_imp:
  "eq_imp (λr'. (λs. ⋃p. WL p s) ⊗ (λs. Set.bind (Option.set_option (sys_heap s r')) (ran ∘ obj_fields)))
          (grey_reachable r)"
by (auto simp: eq_imp_def grey_reachable_def grey_def set_eq_iff reaches_fields)

lemmas grey_reachable_fun_upd[simp] = eq_imp_fun_upd[OF grey_reachable_eq_imp, simplified eq_imp_simps, rule_format]

lemma grey_reachableI[intro]:
  "grey g s ⟹ grey_reachable g s"
unfolding grey_reachable_def reaches_def by blast

lemma grey_reachableE:
  "⟦ (g points_to y) s; grey_reachable g s ⟧ ⟹ grey_reachable y s"
unfolding grey_reachable_def reaches_def by (auto elim: rtranclp.intros(2))


subsection‹valid refs inv›

lemma valid_refs_invI:
  "⟦ ⋀m x y. ⟦ (x reaches y) s; mut_m.root m x s ∨ grey x s ⟧ ⟹ valid_ref y s
   ⟧ ⟹ valid_refs_inv s"
by (auto simp: valid_refs_inv_def mut_m.reachable_def grey_reachable_def)

lemma valid_refs_inv_eq_imp:
  "eq_imp (λ(m', r'). (λs. roots (s (mutator m'))) ⊗ (λs. ghost_honorary_root (s (mutator m'))) ⊗ (λs. map_option obj_fields (sys_heap s r')) ⊗ tso_pending_mutate (mutator m') ⊗ (λs. ⋃p. WL p s))
          valid_refs_inv"
apply (clarsimp simp: eq_imp_def valid_refs_inv_def grey_reachable_def all_conj_distrib)
apply (rename_tac s s')
apply (subgoal_tac "∀r'. valid_ref r' s ⟷ valid_ref r' s'")
 apply (subgoal_tac "∀r'. ⋃(ran ` obj_fields ` set_option (sys_heap s r')) = ⋃(ran ` obj_fields ` set_option (sys_heap s' r'))")
  apply (subst eq_impD[OF mut_m.reachable_eq_imp])
   defer
   apply (subst eq_impD[OF grey_eq_imp])
    defer
    apply (subst eq_impD[OF reaches_eq_imp])
     defer
     apply force
    apply (metis option.set_map)
   apply (clarsimp split: obj_at_splits)
   apply (metis (no_types, opaque_lifting) None_eq_map_option_iff option.exhaust)
  apply clarsimp
 apply clarsimp
apply clarsimp
done

lemmas valid_refs_inv_fun_upd[simp] = eq_imp_fun_upd[OF valid_refs_inv_eq_imp, simplified eq_imp_simps, rule_format]

lemma valid_refs_invD[elim]:
  "⟦ x ∈ mut_m.mut_roots m s; (x reaches y) s; valid_refs_inv s ⟧ ⟹ valid_ref y s"
  "⟦ x ∈ mut_m.mut_roots m s; (x reaches y) s; valid_refs_inv s ⟧ ⟹ ∃obj. sys_heap s y = Some obj"
  "⟦ x ∈ mut_m.tso_store_refs m s; (x reaches y) s; valid_refs_inv s ⟧ ⟹ valid_ref y s"
  "⟦ x ∈ mut_m.tso_store_refs m s; (x reaches y) s; valid_refs_inv s ⟧ ⟹ ∃obj. sys_heap s y = Some obj"
  "⟦ w ∈ set (sys_mem_store_buffers (mutator m) s); x ∈ store_refs w; (x reaches y) s; valid_refs_inv s ⟧ ⟹ valid_ref y s"
  "⟦ w ∈ set (sys_mem_store_buffers (mutator m) s); x ∈ store_refs w; (x reaches y) s; valid_refs_inv s ⟧ ⟹ ∃obj. sys_heap s y = Some obj"
  "⟦ grey x s; (x reaches y) s; valid_refs_inv s ⟧ ⟹ valid_ref y s"
  "⟦ mut_m.reachable m x s; valid_refs_inv s ⟧ ⟹ valid_ref x s"
  "⟦ mut_m.reachable m x s; valid_refs_inv s ⟧ ⟹ ∃obj. sys_heap s x = Some obj"
  "⟦ x ∈ mut_m.mut_ghost_honorary_root m s; (x reaches y) s; valid_refs_inv s ⟧ ⟹ valid_ref y s"
  "⟦ x ∈ mut_m.mut_ghost_honorary_root m s; (x reaches y) s; valid_refs_inv s ⟧ ⟹ ∃obj. sys_heap s y = Some obj"
apply (simp_all add: valid_refs_inv_def grey_reachable_def mut_m.reachable_def mut_m.tso_store_refs_def
              split: obj_at_splits)
apply blast+
done


text‹reachable snapshot inv›

context mut_m
begin

lemma reachable_snapshot_invI[intro]:
  "(⋀y. reachable y s ⟹ in_snapshot y s) ⟹ reachable_snapshot_inv s"
by (simp add: reachable_snapshot_inv_def)

lemma reachable_snapshot_inv_eq_imp:
  "eq_imp (λr'. mut_roots ⊗ mut_ghost_honorary_root ⊗ (λs. r' ∈ (⋃p. WL p s)) ⊗ sys_fM
            ⊗ (λs. ⋃(ran ` obj_fields ` set_option (sys_heap s r'))) ⊗ (λs. map_option obj_mark (sys_heap s r'))
            ⊗ tso_pending_mutate (mutator m))
          reachable_snapshot_inv"
unfolding eq_imp_def mut_m.reachable_snapshot_inv_def in_snapshot_def grey_protects_white_def black_def grey_def
apply (clarsimp simp: all_conj_distrib)
apply (rename_tac s s')
apply (subst (1) eq_impD[OF has_white_path_to_eq_imp])
 apply force
apply (subst eq_impD[OF reachable_eq_imp])
 apply force
apply (subgoal_tac "∀x. obj_at (λobj. obj_mark obj = sys_fM s') x s ⟷ obj_at (λobj. obj_mark obj = sys_fM s') x s'")
 apply force
apply (clarsimp split: obj_at_splits)
apply (rename_tac x)
apply (drule_tac x=x in spec)+
apply (case_tac "sys_heap s x", simp_all)
apply (case_tac "sys_heap s' x", simp_all)
done

end

lemmas reachable_snapshot_fun_upd[simp] = eq_imp_fun_upd[OF mut_m.reachable_snapshot_inv_eq_imp, simplified eq_imp_simps, rule_format]

lemma in_snapshotI[intro]:
  "black r s ⟹ in_snapshot r s"
  "grey r s ⟹ in_snapshot r s"
  "⟦ white w s; (g grey_protects_white w) s ⟧ ⟹ in_snapshot w s"
by (auto simp: in_snapshot_def)

lemma ― ‹Sanity›
  "in_snapshot r s ⟹ black r s ∨ grey r s ∨ white r s"
by (auto simp: in_snapshot_def)

lemma in_snapshot_valid_ref:
  "⟦ in_snapshot r s; valid_refs_inv s ⟧ ⟹ valid_ref r s"
by (metis blackD(1) grey_protects_whiteD grey_protects_white_reaches in_snapshot_def obj_at_cong obj_at_def option.case(2) valid_refs_invD(7))

lemma reachableI2[intro]:
  "x ∈ mut_m.mut_ghost_honorary_root m s ⟹ mut_m.reachable m x s"
unfolding mut_m.reachable_def reaches_def by blast

lemma tso_pending_mw_mutate_cong:
  "⟦ filter is_mw_Mutate (sys_mem_store_buffers p s) = filter is_mw_Mutate (sys_mem_store_buffers p s');
     ⋀r f r'. P r f r' ⟷ Q r f r' ⟧
     ⟹ (∀r f r'. mw_Mutate r f r' ∈ set (sys_mem_store_buffers p s)  ⟶ P r f r')
     ⟷ (∀r f r'. mw_Mutate r f r' ∈ set (sys_mem_store_buffers p s') ⟶ Q r f r')"
by (intro iff_allI) (auto dest!: arg_cong[where f=set])

lemma (in mut_m) marked_insertions_eq_imp:
  "eq_imp (λr'. sys_fM ⊗ (λs. map_option obj_mark (sys_heap s r')) ⊗ tso_pending_mw_mutate (mutator m))
          marked_insertions"
unfolding eq_imp_def marked_insertions_def obj_at_def
apply (clarsimp split: mem_store_action.splits)
apply (erule tso_pending_mw_mutate_cong)
apply (clarsimp split: option.splits obj_at_splits)
apply (rename_tac s s' opt x)
apply (drule_tac x=x in spec)
apply auto
done

lemmas marked_insertions_fun_upd[simp] = eq_imp_fun_upd[OF mut_m.marked_insertions_eq_imp, simplified eq_imp_simps, rule_format]

lemma marked_insertionD[elim!]:
  "⟦ sys_mem_store_buffers (mutator m) s = mw_Mutate r f (Some r') # ws; mut_m.marked_insertions m s ⟧
     ⟹ marked r' s"
by (auto simp: mut_m.marked_insertions_def)

lemma marked_insertions_store_buffer_empty[intro]:
  "tso_pending_mutate (mutator m) s = [] ⟹ mut_m.marked_insertions m s"
unfolding mut_m.marked_insertions_def by (auto simp: filter_empty_conv split: mem_store_action.splits)

(* marked_deletions *)

lemma (in mut_m) marked_deletions_eq_imp:
  "eq_imp (λr'. sys_fM ⊗ (λs. map_option obj_fields (sys_heap s r')) ⊗ (λs. map_option obj_mark (sys_heap s r')) ⊗ tso_pending_mw_mutate (mutator m))
          marked_deletions"
unfolding eq_imp_def marked_deletions_def obj_at_field_on_heap_def ran_def
apply (clarsimp simp: all_conj_distrib)
apply (drule arg_cong[where f=set])
apply (subgoal_tac "∀x. marked x s ⟷ marked x s'")
 apply (clarsimp cong: option.case_cong)
 apply (rule iffI; clarsimp simp: set_eq_iff split: option.splits mem_store_action.splits; blast)
apply clarsimp
apply (rename_tac s s' x)
apply (drule_tac x=x in spec)+
apply (force split: obj_at_splits)
done

lemmas marked_deletions_fun_upd[simp] = eq_imp_fun_upd[OF mut_m.marked_deletions_eq_imp, simplified eq_imp_simps, rule_format]

lemma marked_deletions_store_buffer_empty[intro]:
  "tso_pending_mutate (mutator m) s = [] ⟹ mut_m.marked_deletions m s"
unfolding mut_m.marked_deletions_def by (auto simp: filter_empty_conv split: mem_store_action.splits)


subsection‹Location-specific simplification rules›

lemma obj_at_ref_sweep_loop_free[simp]:
  "obj_at P r (s(sys := (s sys)⦇heap := (sys_heap s)(r' := None)⦈)) ⟷ obj_at P r s ∧ r ≠ r'"
by (clarsimp simp: fun_upd_apply split: obj_at_splits)

lemma obj_at_alloc[simp]:
  "sys_heap s r' = None
  ⟹ obj_at P r (s(m := mut_m_s', sys := (s sys)⦇ heap := (sys_heap s)(r' ↦ obj) ⦈))
  ⟷ (obj_at P r s ∨ (r = r' ∧ P obj))"
unfolding ran_def by (simp add: fun_upd_apply split: obj_at_splits)

lemma valid_ref_valid_null_ref_simps[simp]:
  "valid_ref r (s(sys := do_store_action w (s sys)⦇mem_store_buffers := (mem_store_buffers (s sys))(p := ws)⦈)) ⟷ valid_ref r s"
  "valid_null_ref r' (s(sys := do_store_action w (s sys)⦇mem_store_buffers := (mem_store_buffers (s sys))(p := ws)⦈)) ⟷ valid_null_ref r' s"
  "valid_null_ref r' (s(mutator m := mut_s', sys := (s sys)⦇ heap := (heap (s sys))(r'' ↦ obj) ⦈)) ⟷ valid_null_ref r' s ∨ r' = Some r''"
unfolding do_store_action_def valid_null_ref_def
by (auto simp: fun_upd_apply
        split: mem_store_action.splits obj_at_splits option.splits)

context mut_m
begin

lemma reachable_load[simp]:
  assumes "sys_load (mutator m) (mr_Ref r f) (s sys) = mv_Ref r'"
  assumes "r ∈ mut_roots s"
  shows "mut_m.reachable m' y (s(mutator m := s (mutator m)⦇ roots := mut_roots s ∪ Option.set_option r' ⦈)) ⟷ mut_m.reachable m' y s" (is "?lhs = ?rhs")
proof(cases "m' = m")
  case True show ?thesis
  proof(rule iffI)
    assume ?lhs with assms True show ?rhs
unfolding sys_load_def
apply clarsimp
apply (clarsimp simp: reachable_def reaches_def tso_store_refs_def sys_load_def fold_stores_def fun_upd_apply)
apply (elim disjE)
   apply blast
  defer
 apply blast
apply blast

apply (fold fold_stores_def)
apply clarsimp
apply (drule (1) fold_stores_points_to)
apply (erule disjE)
 apply (fastforce elim!: converse_rtranclp_into_rtranclp[rotated] split: obj_at_splits intro!: ranI)
apply (clarsimp split: mem_store_action.splits)
apply meson
done
  next
    assume ?rhs with True show ?lhs unfolding mut_m.reachable_def by (fastforce simp: fun_upd_apply)
  qed
qed (simp add: fun_upd_apply)

end

text‹WL›

lemma WL_blacken[simp]:
  "gc_ghost_honorary_grey s = {}
    ⟹ WL p (s(gc := s gc⦇ W := gc_W s - rs ⦈)) = WL p s - { r |r. p = gc ∧ r ∈ rs }"
unfolding WL_def by (auto simp: fun_upd_apply)

lemma WL_hs_done[simp]:
  "ghost_honorary_grey (s (mutator m)) = {}
     ⟹ WL p (s(mutator m := s (mutator m)⦇ W := {}, ghost_hs_phase := hp' ⦈,
                 sys   := s sys⦇ hs_pending := hsp', W := sys_W s ∪ W (s (mutator m)),
                                 ghost_hs_in_sync := in' ⦈))
      = (case p of gc ⇒ WL gc s | mutator m' ⇒ (if m' = m then {} else WL (mutator m') s) | sys ⇒ WL sys s ∪ WL (mutator m) s)"
  "ghost_honorary_grey (s (mutator m)) = {}
     ⟹ WL p (s(mutator m := s (mutator m)⦇ W := {} ⦈,
                 sys   := s sys⦇ hs_pending := hsp', W := sys_W s ∪ W (s (mutator m)),
                                 ghost_hs_in_sync := in' ⦈))
      = (case p of gc ⇒ WL gc s | mutator m' ⇒ (if m' = m then {} else WL (mutator m') s) | sys ⇒ WL sys s ∪ WL (mutator m) s)"
unfolding WL_def by (auto simp: fun_upd_apply split: process_name.splits)

lemma colours_load_W[iff]:
  "gc_W s = {} ⟹ black r (s(gc := (s gc)⦇W := W (s sys)⦈, sys := (s sys)⦇W := {}⦈)) ⟷ black r s"
  "gc_W s = {} ⟹ grey r (s(gc := (s gc)⦇W := W (s sys)⦈, sys := (s sys)⦇W := {}⦈)) ⟷ grey r s"
unfolding black_def grey_def WL_def
apply (simp_all add: fun_upd_apply)
apply safe
apply (case_tac [!] x)
apply blast+
done

lemma WL_load_W[simp]:
  "gc_W s = {}
    ⟹ (WL p (s(gc := (s gc)⦇W := sys_W s⦈, sys := (s sys)⦇W := {}⦈)))
     = (case p of gc ⇒ WL gc s ∪ sys_W s | mutator m ⇒ WL (mutator m) s | sys ⇒ sys_ghost_honorary_grey s)"
unfolding WL_def by (auto simp: fun_upd_apply split: process_name.splits)

text‹no grey refs›

lemma no_grey_refs_eq_imp:
  "eq_imp (λ(_::unit). (λs. ⋃p. WL p s))
          no_grey_refs"
by (auto simp add: eq_imp_def grey_def no_grey_refs_def set_eq_iff)

lemmas no_grey_refs_fun_upd[simp] = eq_imp_fun_upd[OF no_grey_refs_eq_imp, simplified eq_imp_simps, rule_format]

lemma no_grey_refs_no_pending_marks:
  "⟦ no_grey_refs s; valid_W_inv s ⟧ ⟹ tso_no_pending_marks s"
unfolding no_grey_refs_def by (auto intro!: filter_False dest: valid_W_invD(2))

lemma no_grey_refs_not_grey_reachableD:
  "no_grey_refs s ⟹ ¬grey_reachable x s"
by (clarsimp simp: no_grey_refs_def grey_reachable_def)

lemma no_grey_refsD:
  "no_grey_refs s ⟹ r ∉ W (s p)"
  "no_grey_refs s ⟹ r ∉ WL p s"
  "no_grey_refs s ⟹ r ∉ ghost_honorary_grey (s p)"
by (auto simp: no_grey_refs_def)

lemma no_grey_refs_marked[dest]:
  "⟦ marked r s; no_grey_refs s ⟧ ⟹ black r s"
by (auto simp: no_grey_refs_def black_def)

lemma no_grey_refs_bwD[dest]:
  "⟦ heap (s sys) r = Some obj; no_grey_refs s ⟧ ⟹ black r s ∨ white r s"
by (clarsimp simp: black_def grey_def no_grey_refs_def white_def split: obj_at_splits)

context mut_m
begin

lemma reachable_blackD:
  "⟦ no_grey_refs s; reachable_snapshot_inv s; reachable r s ⟧ ⟹ black r s"
by (simp add: no_grey_refs_def reachable_snapshot_inv_def in_snapshot_def grey_protects_white_def)

lemma no_grey_refs_not_reachable:
  "⟦ no_grey_refs s; reachable_snapshot_inv s; white r s ⟧ ⟹ ¬reachable r s"
by (fastforce simp: no_grey_refs_def reachable_snapshot_inv_def in_snapshot_def grey_protects_white_def
             split: obj_at_splits)

lemma no_grey_refs_not_rootD:
  "⟦ no_grey_refs s; reachable_snapshot_inv s; white r s ⟧
     ⟹ r ∉ mut_roots s ∧ r ∉ mut_ghost_honorary_root s ∧ r ∉ tso_store_refs s"
apply (drule (2) no_grey_refs_not_reachable)
apply (force simp: reachable_def reaches_def)
done

lemma reachable_snapshot_inv_white_root:
  "⟦ white w s; w ∈ mut_roots s ∨ w ∈ mut_ghost_honorary_root s; reachable_snapshot_inv s ⟧ ⟹ ∃g. (g grey_protects_white w) s"
unfolding reachable_snapshot_inv_def in_snapshot_def reachable_def grey_protects_white_def reaches_def by auto

end

(* colours *)

lemma black_dequeue_Mark[simp]:
  "black b (s(sys := (s sys)⦇ heap := (sys_heap s)(r := map_option (obj_mark_update (λ_. fl)) (sys_heap s r)), mem_store_buffers := (mem_store_buffers (s sys))(p := ws) ⦈))
⟷ (black b s ∧ b ≠ r) ∨ (b = r ∧ fl = sys_fM s ∧ valid_ref r s ∧ ¬grey r s)"
unfolding black_def by (auto simp: fun_upd_apply split: obj_at_splits)

lemma colours_sweep_loop_free[iff]:
  "black r (s(sys := s sys⦇heap := (heap (s sys))(r' := None)⦈)) ⟷ (black r s ∧ r ≠ r')"
  "grey r (s(sys := s sys⦇heap := (heap (s sys))(r' := None)⦈)) ⟷ (grey r s)"
  "white r (s(sys := s sys⦇heap := (heap (s sys))(r' := None)⦈)) ⟷ (white r s ∧ r ≠ r')"
unfolding black_def grey_def white_def by (auto simp: fun_upd_apply split: obj_at_splits)

lemma colours_get_work_done[simp]:
  "black r (s(mutator m := (s (mutator m))⦇W := {}⦈,
              sys := (s sys)⦇ hs_pending := hp', W := W (s sys) ∪ W (s (mutator m)),
                              ghost_hs_in_sync := his' ⦈)) ⟷ black r s"
  "grey r (s(mutator m := (s (mutator m))⦇W := {}⦈,
              sys := (s sys)⦇ hs_pending := hp', W := W (s sys) ∪ W (s (mutator m)),
                              ghost_hs_in_sync := his' ⦈)) ⟷ grey r s"
  "white r (s(mutator m := (s (mutator m))⦇W := {}⦈,
              sys := (s sys)⦇ hs_pending := hp', W := W (s sys) ∪ W (s (mutator m)),
                              ghost_hs_in_sync := his' ⦈)) ⟷ white r s"
unfolding black_def grey_def WL_def
apply (simp_all add: fun_upd_apply split: obj_at_splits)
 apply blast
apply (metis process_name.distinct(3))
done

lemma colours_get_roots_done[simp]:
  "black r (s(mutator m := (s (mutator m))⦇ W := {}, ghost_hs_phase := hs' ⦈,
              sys := (s sys)⦇ hs_pending := hp', W := W (s sys) ∪ W (s (mutator m)),
                              ghost_hs_in_sync := his' ⦈)) ⟷ black r s"
  "grey r (s(mutator m := (s (mutator m))⦇ W := {}, ghost_hs_phase := hs' ⦈,
              sys := (s sys)⦇ hs_pending := hp', W := W (s sys) ∪ W (s (mutator m)),
                              ghost_hs_in_sync := his' ⦈)) ⟷ grey r s"
  "white r (s(mutator m := (s (mutator m))⦇ W := {}, ghost_hs_phase := hs' ⦈,
              sys := (s sys)⦇ hs_pending := hp', W := W (s sys) ∪ W (s (mutator m)),
                              ghost_hs_in_sync := his' ⦈)) ⟷ white r s"
unfolding black_def grey_def WL_def
apply (simp_all add: fun_upd_apply split: obj_at_splits)
 apply blast
apply (metis process_name.distinct(3))
done

lemma colours_flip_fM[simp]:
  "fl ≠ sys_fM s ⟹ black b (s(sys := (s sys)⦇fM := fl, mem_store_buffers := (mem_store_buffers (s sys))(p := ws)⦈)) ⟷ white b s ∧ ¬grey b s"
unfolding black_def white_def by (simp add: fun_upd_apply)

lemma colours_alloc[simp]:
  "heap (s sys) r' = None
     ⟹ black r (s(mutator m := (s (mutator m))⦇ roots := roots' ⦈, sys := (s sys)⦇heap := (heap (s sys))(r' ↦ ⦇obj_mark = fl, obj_fields = Map.empty, obj_payload = Map.empty⦈)⦈))
     ⟷ black r s ∨ (r' = r ∧ fl = sys_fM s ∧ ¬grey r' s)"
  "grey r (s(mutator m := (s (mutator m))⦇ roots := roots' ⦈, sys := (s sys)⦇heap := (heap (s sys))(r' ↦ ⦇obj_mark = fl, obj_fields = Map.empty, obj_payload = Map.empty⦈)⦈))
     ⟷ grey r s"
  "heap (s sys) r' = None
     ⟹ white r (s(mutator m := (s (mutator m))⦇ roots := roots' ⦈, sys := (s sys)⦇heap := (heap (s sys))(r' ↦ ⦇obj_mark = fl, obj_fields = Map.empty, obj_payload = Map.empty⦈)⦈))
     ⟷ white r s ∨ (r' = r ∧ fl ≠ sys_fM s)"
unfolding black_def white_def by (auto simp: fun_upd_apply split: obj_at_splits)

lemma heap_colours_alloc[simp]:
  "⟦ heap (s sys) r' = None; valid_refs_inv s ⟧
  ⟹ black_heap (s(mutator m := s (mutator m)⦇roots := roots'⦈, sys := s sys⦇heap := (sys_heap s)(r' ↦ ⦇obj_mark = fl, obj_fields = Map.empty, obj_payload = Map.empty⦈)⦈))
  ⟷ black_heap s ∧ fl = sys_fM s"
  "heap (s sys) r' = None
  ⟹ white_heap (s(mutator m := s (mutator m)⦇roots := roots'⦈, sys := s sys⦇heap := (sys_heap s)(r' ↦ ⦇obj_mark = fl, obj_fields = Map.empty, obj_payload = Map.empty⦈)⦈))
  ⟷ white_heap s ∧ fl ≠ sys_fM s"
unfolding black_heap_def white_def white_heap_def
apply (simp_all add: fun_upd_apply split: obj_at_splits)
 apply (rule iffI)
  apply (intro allI conjI impI)
   apply (rename_tac x)
   apply (drule_tac x=x in spec)
   apply clarsimp
  apply (drule spec[where x=r'], auto simp: reaches_def dest!: valid_refs_invD split: obj_at_splits)[2]
apply (rule iffI)
 apply (intro allI conjI impI)
  apply (rename_tac x obj)
  apply (drule_tac x=x in spec)
  apply clarsimp
 apply (drule spec[where x=r'], auto dest!: valid_refs_invD split: obj_at_splits)[2]
done

lemma grey_protects_white_hs_done[simp]:
  "(g grey_protects_white w) (s(mutator m := s (mutator m)⦇ W := {}, ghost_hs_phase := hs' ⦈,
                              sys := s sys⦇ hs_pending := hp', W := sys_W s ∪ W (s (mutator m)),
                                            ghost_hs_in_sync := his' ⦈))
  ⟷ (g grey_protects_white w) s"
unfolding grey_protects_white_def by (simp add: fun_upd_apply)

lemma grey_protects_white_alloc[simp]:
  "⟦ fl = sys_fM s; sys_heap s r = None ⟧
     ⟹ (g grey_protects_white w) (s(mutator m := s (mutator m)⦇roots := roots'⦈, sys := s sys⦇heap := (sys_heap s)(r ↦ ⦇obj_mark = fl, obj_fields = Map.empty, obj_payload = Map.empty⦈)⦈))
     ⟷ (g grey_protects_white w) s"
unfolding grey_protects_white_def has_white_path_to_def by simp

lemma (in mut_m) reachable_snapshot_inv_sweep_loop_free:
  fixes s :: "('field, 'mut, 'payload, 'ref) lsts"
  assumes nmr: "white r s"
  assumes ngs: "no_grey_refs s"
  assumes rsi: "reachable_snapshot_inv s"
  shows "reachable_snapshot_inv (s(sys := (s sys)⦇heap := (heap (s sys))(r := None)⦈))" (is "reachable_snapshot_inv ?s'")
proof
  fix y :: "'ref"
  assume rx: "reachable y ?s'"
  then have "black y s ∧ y ≠ r"
  proof(induct rule: reachable_induct)
    case (root x) with ngs nmr rsi show ?case
      by (auto simp: fun_upd_apply dest: reachable_blackD)
  next
    case (ghost_honorary_root x) with ngs nmr rsi show ?case
      unfolding reachable_def reaches_def by (auto simp: fun_upd_apply dest: reachable_blackD)
  next
    case (tso_root x) with ngs nmr rsi show ?case
      unfolding reachable_def reaches_def by (auto simp: fun_upd_apply dest: reachable_blackD)
  next
    case (reaches x y) with ngs nmr rsi show ?case
      unfolding reachable_def reaches_def
      apply (clarsimp simp: fun_upd_apply)
      apply (drule predicate2D[OF rtranclp_mono[where s="λx y. (x points_to y) s", OF predicate2I], rotated])
       apply (clarsimp split: obj_at_splits if_splits)
      apply (rule conjI)
       apply (rule reachable_blackD, assumption, assumption)
       apply (simp add: reachable_def reaches_def)
       apply (blast intro: rtranclp.intros(2))
      apply clarsimp
      apply (frule (1) reachable_blackD[where r=r])
       apply (simp add: reachable_def reaches_def)
       apply (blast intro: rtranclp.intros(2))
      apply auto
      done
  qed
  then show "in_snapshot y ?s'"
    unfolding in_snapshot_def by simp
qed

lemma reachable_alloc[simp]:
  assumes rn: "sys_heap s r = None"
  shows "mut_m.reachable m r' (s(mutator m' := (s (mutator m'))⦇roots := insert r (roots (s (mutator m')))⦈, sys := (s sys)⦇heap := (sys_heap s)(r ↦ ⦇obj_mark = fl, obj_fields = Map.empty, obj_payload = Map.empty⦈)⦈))
     ⟷ mut_m.reachable m r' s ∨ (m' = m ∧ r' = r)" (is "?lhs ⟷ ?rhs")
proof(rule iffI)
  assume ?lhs from this assms show ?rhs
  proof(induct rule: reachable_induct)
    case (reaches x y) then show ?case by clarsimp (fastforce simp: mut_m.reachable_def reaches_def elim: rtranclp.intros(2) split: obj_at_splits)
  qed (auto simp: fun_upd_apply split: if_splits)
next
  assume ?rhs then show ?lhs
  proof(rule disjE)
    assume "mut_m.reachable m r' s" then show ?thesis
    proof(induct rule: reachable_induct)
      case (tso_root x) then show ?case
        unfolding mut_m.reachable_def by fastforce
    next
      case (reaches x y) with rn show ?case
        unfolding mut_m.reachable_def by fastforce
    qed (auto simp: fun_upd_apply)
  next
    assume "m' = m ∧ r' = r" with rn show ?thesis
      unfolding mut_m.reachable_def by (fastforce simp: fun_upd_apply)
  qed
qed

context mut_m
begin

lemma reachable_snapshot_inv_alloc[simp, elim!]:
  fixes s :: "('field, 'mut, 'payload, 'ref) lsts"
  assumes rsi: "reachable_snapshot_inv s"
  assumes rn: "sys_heap s r = None"
  assumes fl: "fl = sys_fM s"
  assumes vri: "valid_refs_inv s"
  shows "reachable_snapshot_inv (s(mutator m' := (s (mutator m'))⦇roots := insert r (roots (s (mutator m')))⦈, sys := (s sys)⦇heap := (sys_heap s)(r ↦ ⦇obj_mark = fl, obj_fields = Map.empty, obj_payload = Map.empty⦈)⦈))"
(is "reachable_snapshot_inv ?s'")
using assms unfolding reachable_snapshot_inv_def in_snapshot_def
by (auto simp del: reachable_fun_upd)

lemma reachable_snapshot_inv_discard_roots[simp]:
  "⟦ reachable_snapshot_inv s; roots' ⊆ roots (s (mutator m)) ⟧
     ⟹ reachable_snapshot_inv (s(mutator m := (s (mutator m))⦇roots := roots'⦈))"
unfolding reachable_snapshot_inv_def reachable_def in_snapshot_def grey_protects_white_def by (auto simp: fun_upd_apply)

lemma reachable_snapshot_inv_load[simp]:
  "⟦ reachable_snapshot_inv s; sys_load (mutator m) (mr_Ref r f) (s sys) = mv_Ref r'; r ∈ mut_roots s ⟧
     ⟹ reachable_snapshot_inv (s(mutator m := s (mutator m)⦇ roots := mut_roots s ∪ Option.set_option r' ⦈))"
unfolding reachable_snapshot_inv_def in_snapshot_def grey_protects_white_def by (simp add: fun_upd_apply)

lemma reachable_snapshot_inv_store_ins[simp]:
  "⟦ reachable_snapshot_inv s; r ∈ mut_roots s; (∃r'. opt_r' = Some r') ⟶ the opt_r' ∈ mut_roots s ⟧
     ⟹ reachable_snapshot_inv (s(mutator m := s (mutator m)⦇ghost_honorary_root := {}⦈,
                                  sys := s sys⦇  mem_store_buffers := (mem_store_buffers (s sys))(mutator m := sys_mem_store_buffers (mutator m) s @ [mw_Mutate r f opt_r']) ⦈))"
unfolding reachable_snapshot_inv_def in_snapshot_def grey_protects_white_def reachable_def
apply clarsimp
apply (drule_tac x=x in spec)
apply (auto simp: fun_upd_apply)
(* FIXME what's gone wrong here? *)
apply (subst (asm) tso_store_refs_simps; force)+
done

end

lemma WL_mo_co_mark[simp]:
  "ghost_honorary_grey (s p) = {}
     ⟹ WL p' (s(p := s p⦇ ghost_honorary_grey := rs ⦈)) = WL p' s ∪ { r |r. p' = p ∧ r ∈ rs}"
unfolding WL_def by (simp add: fun_upd_apply)

lemma ghost_honorary_grey_mo_co_mark[simp]:
  "⟦ ghost_honorary_grey (s p) = {} ⟧ ⟹ black b (s(p := s p⦇ghost_honorary_grey := {r}⦈)) ⟷ black b s ∧ b ≠ r"
  "⟦ ghost_honorary_grey (s p) = {} ⟧ ⟹ grey g (s(p := (s p)⦇ghost_honorary_grey := {r}⦈)) ⟷ grey g s ∨ g = r"
  "⟦ ghost_honorary_grey (s p) = {} ⟧ ⟹ white w (s(p := s p⦇ghost_honorary_grey := {r}⦈))  ⟷ white w s"
unfolding black_def grey_def by (auto simp: fun_upd_apply)

lemma ghost_honorary_grey_mo_co_W[simp]:
  "ghost_honorary_grey (s p') = {r}
     ⟹ (WL p (s(p' := (s p')⦇W := insert r (W (s p')), ghost_honorary_grey := {}⦈))) = (WL p s)"
  "ghost_honorary_grey (s p') = {r}
     ⟹ grey g (s(p' := (s p')⦇W := insert r (W (s p')), ghost_honorary_grey := {}⦈)) ⟷ grey g s"
unfolding grey_def WL_def by (auto simp: fun_upd_apply split: process_name.splits if_splits)

lemma reachable_sweep_loop_free:
  "mut_m.reachable m r (s(sys := s sys⦇heap := (sys_heap s)(r' := None)⦈))
   ⟹ mut_m.reachable m r s"
unfolding mut_m.reachable_def reaches_def by (clarsimp simp: fun_upd_apply) (metis (no_types, lifting) mono_rtranclp)

lemma reachable_deref_del[simp]:
  "⟦ sys_load (mutator m) (mr_Ref r f) (s sys) = mv_Ref opt_r'; r ∈ mut_m.mut_roots m s; mut_m.mut_ghost_honorary_root m s = {} ⟧
   ⟹ mut_m.reachable m' y (s(mutator m := s (mutator m)⦇ ghost_honorary_root := Option.set_option opt_r', ref := opt_r' ⦈))
   ⟷ mut_m.reachable m' y s"
unfolding mut_m.reachable_def reaches_def sys_load_def
apply (clarsimp simp: fun_upd_apply)
apply (rule iffI)
 apply clarsimp
 apply (elim disjE)
   apply metis
  apply (erule option_bind_invE; auto dest!: fold_stores_points_to)
 apply (auto elim!: converse_rtranclp_into_rtranclp[rotated]
              simp: mut_m.tso_store_refs_def)
done

lemma no_black_refs_dequeue[simp]:
  "⟦ sys_mem_store_buffers p s = mw_Mark r fl # ws; no_black_refs s; valid_W_inv s ⟧
   ⟹ no_black_refs (s(sys := s sys⦇heap := (sys_heap s)(r := map_option (obj_mark_update (λ_. fl)) (sys_heap s r)), mem_store_buffers := (mem_store_buffers (s sys))(p := ws)⦈))"
  "⟦ sys_mem_store_buffers p s = mw_Mutate r f r' # ws; no_black_refs s ⟧
     ⟹ no_black_refs (s(sys := s sys⦇heap := (sys_heap s)(r := map_option (λobj. obj⦇obj_fields := (obj_fields obj)(f := r')⦈) (sys_heap s r)),
                                      mem_store_buffers := (mem_store_buffers (s sys))(p := ws)⦈))"
unfolding no_black_refs_def by (auto simp: fun_upd_apply dest: valid_W_invD)

lemma colours_blacken[simp]:
  "valid_W_inv s ⟹ black b (s(gc := s gc⦇W := gc_W s - {r}⦈)) ⟷ black b s ∨ (r ∈ gc_W s ∧ b = r)"
  "⟦ r ∈ gc_W s; valid_W_inv s ⟧ ⟹ grey g (s(gc := s gc⦇W := gc_W s - {r}⦈)) ⟷ (grey g s ∧ g ≠ r)"
  (*  "white w (s(gc := s gc⦇W := gc_W s - {r}⦈)) ⟷ white w s" is redundant *)
unfolding black_def grey_def valid_W_inv_def
apply (simp_all add: all_conj_distrib split: obj_at_splits if_splits)
apply safe
apply (simp_all add: WL_def fun_upd_apply split: if_splits)
  apply (metis option.distinct(1))
apply blast
apply blast
apply blast
apply blast
apply blast
apply blast
apply metis
done
(* FIXME
apply (auto simp: black_def grey_def WL_def split: obj_at_splits)
apply metis+
done
*)

lemma no_black_refs_alloc[simp]:
  "⟦ heap (s sys) r' = None; no_black_refs s ⟧
     ⟹ no_black_refs (s(mutator m' := s (mutator m')⦇roots := roots'⦈, sys := s sys⦇heap := (sys_heap s)(r' ↦ ⦇obj_mark = fl, obj_fields = Map.empty, obj_payload = Map.empty⦈)⦈))
     ⟷ fl ≠ sys_fM s ∨ grey r' s"
unfolding no_black_refs_def by simp

lemma no_black_refs_mo_co_mark[simp]:
  "⟦ ghost_honorary_grey (s p) = {}; white r s ⟧
     ⟹ no_black_refs (s(p := s p⦇ghost_honorary_grey := {r}⦈)) ⟷ no_black_refs s"
unfolding no_black_refs_def by auto

lemma grey_protects_white_mark[simp]:
  assumes ghg: "ghost_honorary_grey (s p) = {}"
  shows "(∃g. (g grey_protects_white w) (s(p := s p⦇ ghost_honorary_grey := {r} ⦈)))
      ⟷ (∃g'. (g' grey_protects_white w) s) ∨ (r has_white_path_to w) s" (is "?lhs ⟷ ?rhs")
proof
  assume ?lhs
  then obtain g where "(g grey_protects_white w) (s(p := s p⦇ghost_honorary_grey := {r}⦈))" by blast
  from this ghg show ?rhs by induct (auto simp: fun_upd_apply)
next
  assume ?rhs then show ?lhs
  proof(safe)
    fix g assume "(g grey_protects_white w) s"
    from this ghg show ?thesis
apply induct
 apply force
unfolding grey_protects_white_def
apply (auto simp: fun_upd_apply)
done
  next
    assume "(r has_white_path_to w) s" with ghg show ?thesis
      unfolding grey_protects_white_def has_white_path_to_def by (auto simp: fun_upd_apply)
  qed
qed

lemma valid_refs_inv_dequeue_Mutate:
  fixes s :: "('field, 'mut, 'payload, 'ref) lsts"
  assumes vri: "valid_refs_inv s"
  assumes sb: "sys_mem_store_buffers (mutator m') s = mw_Mutate r f opt_r' # ws"
  shows "valid_refs_inv (s(sys := s sys⦇heap := (sys_heap s)(r := map_option (λobj. obj⦇obj_fields := (obj_fields obj)(f := opt_r')⦈) (sys_heap s r)),
                                        mem_store_buffers := (mem_store_buffers (s sys))(mutator m' := ws)⦈))" (is "valid_refs_inv ?s'")
proof(rule valid_refs_invI)
  fix m
  let ?root = "λm x. mut_m.root m x ∨ grey x"
  fix x y assume xy: "(x reaches y) ?s'" and x: "?root m x ?s'"
  from xy have "(∃m x. ?root m x s ∧ (x reaches y) s) ∧ valid_ref y ?s'"
  unfolding reaches_def proof induct
    case base with x sb vri show ?case
      apply -
      apply (subst obj_at_fun_upd)
       apply (auto simp: mut_m.tso_store_refs_def reaches_def fun_upd_apply split: if_splits intro: valid_refs_invD(5)[where m=m])
      apply (metis list.set_intros(2) rtranclp.rtrancl_refl)
      done (* FIXME rules *)
  next
    case (step y z)
    with sb vri show ?case
      apply -
      apply (subst obj_at_fun_upd, clarsimp simp: fun_upd_apply)
      apply (subst (asm) obj_at_fun_upd, fastforce simp: fun_upd_apply)
      apply (clarsimp simp: points_to_Mutate fun_upd_apply)
      apply (fastforce elim: rtranclp.intros(2) simp: mut_m.tso_store_refs_def reaches_def fun_upd_apply intro: exI[where x=m'] valid_refs_invD(5)[where m=m'])
      done
   qed
  then show "valid_ref y ?s'" by blast
qed

lemma valid_refs_inv_dequeue_Mutate_Payload:
  notes if_split_asm[split del]
  fixes s :: "('field, 'mut, 'payload, 'ref) lsts"
  assumes vri: "valid_refs_inv s"
  assumes sb: "sys_mem_store_buffers (mutator m') s = mw_Mutate_Payload r f pl # ws"
  shows "valid_refs_inv (s(sys := s sys⦇heap := (sys_heap s)(r := map_option (λobj. obj⦇obj_payload := (obj_payload obj)(f := pl)⦈) (sys_heap s r)),
                                        mem_store_buffers := (mem_store_buffers (s sys))(mutator m := ws)⦈))" (is "valid_refs_inv ?s'")
apply (rule valid_refs_invI)
using assms
apply (clarsimp simp: valid_refs_invD fun_upd_apply split: obj_at_splits mem_store_action.splits)
apply auto
 apply (metis (mono_tags, lifting) UN_insert Un_iff list.simps(15) mut_m.tso_store_refs_def valid_refs_invD(4))
apply (metis case_optionE obj_at_def valid_refs_invD(7))
done

(*<*)

end
(*>*)