Theory StrongTricolour

(*<*)
(*
 * 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 StrongTricolour
imports
  Global_Invariants_Lemmas
  Local_Invariants_Lemmas
  Tactics
begin

(*>*)

(* local lemma bucket *)

context mut_m
begin

(* marked insertions *)

lemma marked_insertions_store_ins[simp]:
  " marked_insertions s; (r'. opt_r' = Some r')  marked (the opt_r') s 
      marked_insertions
               (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'])))"
by (auto simp: marked_insertions_def
        split: mem_store_action.splits option.splits)

lemma marked_insertions_alloc[simp]:
  " heap (s sys) r' = None; valid_refs_inv s 
   marked_insertions (s(mutator m' := s (mutator m')roots := roots', sys := s sysheap := (sys_heap s)(r'  obj')))
   marked_insertions s"
apply (clarsimp simp: marked_insertions_def split: mem_store_action.splits option.splits)
apply (rule iffI)
 apply clarsimp
 apply (rename_tac ref field x)
 apply (drule_tac x=ref in spec, drule_tac x=field in spec, drule_tac x=x in spec, clarsimp)
 apply (drule valid_refs_invD(6)[where x=r' and y=r'], simp_all)
done


(* marked_deletions *)

lemma marked_deletions_store_ins[simp]:
  " marked_deletions s; obj_at_field_on_heap (λr'. marked r' s) r f s 
      marked_deletions
               (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'])))"
by (auto simp: marked_deletions_def
        split: mem_store_action.splits option.splits)

lemma marked_deletions_alloc[simp]:
  " marked_deletions s; heap (s sys) r' = None; valid_refs_inv s 
   marked_deletions (s(mutator m' := s (mutator m')roots := roots', sys := s sysheap := (sys_heap s)(r'  obj')))"
apply (clarsimp simp: marked_deletions_def split: mem_store_action.splits)
apply (rename_tac ref field option)
apply (drule_tac x="mw_Mutate ref field option" in spec)
apply clarsimp
apply (case_tac "ref = r'")
 apply (auto simp: obj_at_field_on_heap_def split: option.splits)
done

end


subsection‹Sweep loop invariants›

lemma (in gc) sweep_loop_invL_eq_imp:
  "eq_imp (λ(_::unit) s. (AT s gc, s gc, sys_fM s, map_option obj_mark  sys_heap s))
          sweep_loop_invL"
apply (clarsimp simp: eq_imp_def inv)
apply (rename_tac s s')
apply (subgoal_tac "r. valid_ref r s  valid_ref r s'")
 apply (subgoal_tac "P r. obj_at (λobj. P (obj_mark obj)) r s  obj_at (λobj. P (obj_mark obj)) r s'")
  apply (frule_tac x="λmark. Some mark = gc_mark s'" in spec)
  apply (frule_tac x="λmark. mark = sys_fM s'" in spec)
  apply clarsimp
 apply (clarsimp simp: fun_eq_iff split: obj_at_splits)
 apply (rename_tac r)
 apply ( (drule_tac x=r in spec)+, auto)[1]
apply (clarsimp simp: fun_eq_iff split: obj_at_splits)
apply (rename_tac r)
apply (drule_tac x=r in spec, auto)[1]
apply (metis map_option_eq_Some)+
done

lemmas gc_sweep_loop_invL_niE[nie] =
  iffD1[OF gc.sweep_loop_invL_eq_imp[simplified eq_imp_simps, rule_format, unfolded conj_explode, rule_format], rotated -1]

lemma (in gc) sweep_loop_invL[intro]:
  " fM_fA_invL  phase_invL  sweep_loop_invL  tso_lock_invL
          LSTP (phase_rel_inv  mutators_phase_inv  valid_W_inv) 
     gc
    sweep_loop_invL "
proof(vcg_jackhammer, vcg_name_cases)
     case sweep_loop_ref_done  then show ?case by blast
next case sweep_loop_check     then show ?case
      apply (clarsimp split: obj_at_splits)
      apply (metis (no_types, lifting) option.collapse option.inject)
      done
next case sweep_loop_load_mark then show ?case by (clarsimp split: obj_at_splits)
qed

context gc
begin

lemma sweep_loop_locs_subseteq_sweep_locs:
  "sweep_loop_locs  sweep_locs"
by (auto simp: sweep_loop_locs_def sweep_locs_def intro: append_prefixD)

lemma sweep_locs_subseteq_fM_tso_empty_locs:
  "sweep_locs  fM_tso_empty_locs"
by (auto simp: sweep_locs_def fM_tso_empty_locs_def loc_defs)

lemma sweep_loop_locs_fM_eq_locs:
  "sweep_loop_locs  fM_eq_locs"
by (auto simp: sweep_loop_locs_def fM_eq_locs_def sweep_locs_def loc_defs)

lemma sweep_loop_locs_fA_eq_locs:
  "sweep_loop_locs  fA_eq_locs"
apply (simp add: sweep_loop_locs_def fA_eq_locs_def sweep_locs_def)
apply (intro subset_insertI2)
apply (auto intro: append_prefixD)
done

lemma black_heap_locs_subseteq_fM_tso_empty_locs:
  "black_heap_locs  fM_tso_empty_locs"
by (auto simp: black_heap_locs_def fM_tso_empty_locs_def loc_defs)

lemma black_heap_locs_fM_eq_locs:
  "black_heap_locs  fM_eq_locs"
by (simp add: black_heap_locs_def fM_eq_locs_def loc_defs)

lemma black_heap_locs_fA_eq_locs:
  "black_heap_locs  fA_eq_locs"
by (simp add: black_heap_locs_def fA_eq_locs_def sweep_locs_def loc_defs)

lemma fM_fA_invL_tso_emptyD:
  " atS gc ls s; fM_fA_invL s; ls  fM_tso_empty_locs   tso_pending_fM gc s = []"
by (auto simp: fM_fA_invL_def dest: atS_mono)

lemma gc_sweep_loop_invL_locsE[rule_format]:
  "(atS gc (sweep_locs  black_heap_locs) s  False)  gc.sweep_loop_invL s"
apply (simp add: gc.sweep_loop_invL_def atS_un)
apply (auto simp: locset_cache atS_simps dest: atS_mono)
 apply (simp add: atS_mono gc.sweep_loop_locs_subseteq_sweep_locs; fail)
apply (clarsimp simp: atS_def)
apply (rename_tac x)
apply (drule_tac x=x in bspec)
apply (auto simp: sweep_locs_def sweep_loop_not_choose_ref_locs_def intro: append_prefixD)
done

end

lemma (in sys) gc_sweep_loop_invL[intro]:
  " gc.fM_fA_invL  gc.gc_W_empty_invL  gc.sweep_loop_invL
        LSTP (tso_store_inv  valid_W_inv) 
     sys
    gc.sweep_loop_invL "
proof(vcg_jackhammer (keep_locs) (no_thin_post_inv), vcg_name_cases)
  case (tso_dequeue_store_buffer s s' p w ws) then show ?case
  proof(cases w)
       case (mw_Mark r fl) with tso_dequeue_store_buffer show ?thesis
        apply -
        apply (rule gc.gc_sweep_loop_invL_locsE)
        apply (simp only: gc.gc_W_empty_invL_def gc.no_grey_refs_locs_def cong del: atS_state_weak_cong)
        apply (clarsimp simp: atS_un)
        apply (thin_tac "AT _ = _") (* FIXME speed the metis call up a bit *)
        apply (thin_tac "at _ _ _  _")+
        apply (metis (mono_tags, lifting) filter.simps(2) loc_mem_tac_simps(4) no_grey_refs_no_pending_marks)
        done
  next case (mw_Mutate r f opt_r') with tso_dequeue_store_buffer show ?thesis by clarsimp (erule gc_sweep_loop_invL_niE; simp add: fun_eq_iff fun_upd_apply)
  next case (mw_Mutate_Payload r f pl) with tso_dequeue_store_buffer show ?thesis by clarsimp (erule gc_sweep_loop_invL_niE; simp add: fun_eq_iff fun_upd_apply)
  next case (mw_fA fl) with tso_dequeue_store_buffer show ?thesis by - (erule gc_sweep_loop_invL_niE; simp add: fun_eq_iff)
  next case (mw_fM fl) with tso_dequeue_store_buffer show ?thesis
        apply -
        apply (rule gc.gc_sweep_loop_invL_locsE)
        apply (case_tac p; clarsimp)
        apply (drule (1) gc.fM_fA_invL_tso_emptyD)
        apply simp_all
        using gc.black_heap_locs_subseteq_fM_tso_empty_locs gc.sweep_locs_subseteq_fM_tso_empty_locs apply blast
        done
  next case (mw_Phase ph) with tso_dequeue_store_buffer show ?thesis by - (erule gc_sweep_loop_invL_niE; simp add: fun_eq_iff)
  qed
qed

lemma (in mut_m) gc_sweep_loop_invL[intro]:
  " gc.fM_fA_invL  gc.handshake_invL  gc.sweep_loop_invL
        LSTP (mutators_phase_inv  valid_refs_inv) 
     mutator m
    gc.sweep_loop_invL "
proof( vcg_chainsaw (no_thin) gc.fM_fA_invL_def gc.sweep_loop_invL_def gc.handshake_invL_def, vcg_name_cases gc)
     case (sweep_loop_locs s s' rb) then show ?case by (metis (no_types, lifting) atS_mono gc.sweep_loop_locs_fA_eq_locs gc.sweep_loop_locs_fM_eq_locs)
next case (black_heap_locs s s' rb) then show ?case by (metis (no_types, lifting) atS_mono gc.black_heap_locs_fA_eq_locs gc.black_heap_locs_fM_eq_locs)
qed


subsection‹ Mutator proofs ›

context mut_m
begin

(* reachable snapshot inv *)

lemma reachable_snapshot_inv_mo_co_mark[simp]:
  " ghost_honorary_grey (s p) = {}; reachable_snapshot_inv s 
      reachable_snapshot_inv (s(p := s p ghost_honorary_grey := {r} ))"
unfolding in_snapshot_def reachable_snapshot_inv_def by (auto simp: fun_upd_apply)

lemma reachable_snapshot_inv_hs_get_roots_done:
  assumes sti: "strong_tricolour_inv s"
  assumes m: "r  mut_roots s. marked r s"
  assumes ghr: "mut_ghost_honorary_root s = {}"
  assumes t: "tso_pending_mutate (mutator m) s = []"
  assumes vri: "valid_refs_inv s"
  shows "reachable_snapshot_inv
               (s(mutator m := s (mutator m)W := {}, ghost_hs_phase := ghp',
                  sys := s syshs_pending := hp', W := sys_W s  mut_W s, ghost_hs_in_sync := in'))"
  (is "reachable_snapshot_inv ?s'")
proof(rule, clarsimp)
  fix r assume "reachable r s"
  then show "in_snapshot r ?s'"
  proof (induct rule: reachable_induct)
    case (root x) with m show ?case
      apply (clarsimp simp: in_snapshot_def) (* FIXME intro rules *)
      apply (auto dest: marked_imp_black_or_grey)
      done
  next
    case (ghost_honorary_root x) with ghr show ?case by simp
  next
    case (tso_root x) with t show ?case
      apply (clarsimp simp: filter_empty_conv tso_store_refs_def)
      apply (rename_tac w; case_tac w; fastforce)
      done
  next
    case (reaches x y)
    from reaches vri have "valid_ref x s" "valid_ref y s"
      using reachable_points_to by fastforce+
    with reaches sti vri show ?case
      apply (clarsimp simp: in_snapshot_def)
      apply (elim disjE)
       apply (clarsimp simp: strong_tricolour_inv_def)
       apply (drule spec[where x=x])
       apply clarsimp
       apply (auto dest!: marked_imp_black_or_grey)[1]
      apply (cases "white y s")
      apply (auto dest: grey_protects_whiteE
                 dest!: marked_imp_black_or_grey)
        done
    qed
qed

lemma reachable_snapshot_inv_hs_get_work_done:
  "reachable_snapshot_inv s
     reachable_snapshot_inv
               (s(mutator m := s (mutator m)W := {},
                   sys := s syshs_pending := pending', W := sys_W s  mut_W s,
                                ghost_hs_in_sync := (ghost_hs_in_sync (s sys))(m := True)))"
by (simp add: reachable_snapshot_inv_def in_snapshot_def grey_protects_white_def)

lemma reachable_snapshot_inv_deref_del:
  " reachable_snapshot_inv s; sys_load (mutator m) (mr_Ref r f) (s sys) = mv_Ref opt_r'; r  mut_roots s; mut_ghost_honorary_root s = {} 
      reachable_snapshot_inv (s(mutator m := s (mutator m)ghost_honorary_root := Option.set_option opt_r', ref := opt_r'))"
unfolding reachable_snapshot_inv_def in_snapshot_def grey_protects_white_def by (clarsimp simp: fun_upd_apply)

lemma mutator_phase_inv[intro]:
  notes fun_upd_apply[simp]
  notes reachable_snapshot_inv_deref_del[simp]
  notes if_split_asm[split del]
  shows
  " handshake_invL
        mark_object_invL
        mut_get_roots.mark_object_invL m
        mut_store_del.mark_object_invL m
        mut_store_ins.mark_object_invL m
        LSTP (handshake_phase_inv  mutators_phase_inv  phase_rel_inv  sys_phase_inv  fA_rel_inv  fM_rel_inv  valid_refs_inv  strong_tricolour_inv  valid_W_inv) 
     mutator m
    LSTP mutator_phase_inv "
proof( vcg_jackhammer (no_thin_post_inv)
    , simp_all add: mutator_phase_inv_aux_case split: hs_phase.splits
    , vcg_name_cases)
     case alloc then show ?case
    apply (drule_tac x=m in spec)
    apply (drule handshake_phase_invD)
    apply (clarsimp simp: fA_rel_inv_def fM_rel_inv_def fM_rel_def hp_step_rel_def split: if_split_asm)
    apply (intro conjI impI; simp)
     apply (elim disjE; force simp: fA_rel_def)
    apply (rule reachable_snapshot_inv_alloc, simp_all)
    apply (elim disjE; force simp: fA_rel_def)
    done
next case (store_ins s s') then show ?case
    apply (drule_tac x=m in spec)
    apply (drule handshake_phase_invD)
    apply (intro conjI impI; clarsimp)
      apply (rule marked_deletions_store_ins, assumption) (* FIXME shuffle the following into this lemma *)
      apply (cases "(opt_r'. mw_Mutate (mut_tmp_ref s) (mut_field s) opt_r'  set (sys_mem_store_buffers (mutator m) s))"; clarsimp)
      apply (force simp: marked_deletions_def)
     apply (erule marked_insertions_store_ins)
     apply (drule phase_rel_invD)
     apply (clarsimp simp: phase_rel_def hp_step_rel_def; elim disjE; fastforce dest: reachable_blackD elim: blackD; fail)
    apply (rule marked_deletions_store_ins; clarsimp) (* FIXME as above *)
    apply (erule disjE; clarsimp)
     apply (drule phase_rel_invD)
     apply (clarsimp simp: phase_rel_def)
     apply (elim disjE; clarsimp)
      apply (fastforce simp: hp_step_rel_def)
     apply (clarsimp simp: hp_step_rel_def)
     apply (case_tac "sys_ghost_hs_phase s"; clarsimp) (* FIXME invert handshake_phase_rel *)
      apply (clarsimp simp: obj_at_field_on_heap_def split: option.splits)
      apply (rule conjI, fast, clarsimp)
      apply (frule_tac r=x2a in blackD(1)[OF reachable_blackD], simp_all)[1]
      apply (rule_tac x="mut_tmp_ref s" in reachable_points_to; auto simp: ran_def split: obj_at_splits; fail)
     apply (clarsimp simp: obj_at_field_on_heap_def split: option.splits)
     apply (rule conjI, fast, clarsimp)
     apply (frule_tac r=x2a in blackD(1)[OF reachable_blackD], simp_all)[1]
     apply (rule_tac x="mut_tmp_ref s" in reachable_points_to; auto simp: ran_def split: obj_at_splits; fail)
    apply (force simp: marked_deletions_def)
    done
next case (hs_noop_done s s') then show ?case
    apply -
    apply (drule_tac x=m in spec)
    apply (drule handshake_phase_invD)
    apply (simp add: fA_rel_def fM_rel_def hp_step_rel_def)
    apply (cases "mut_ghost_hs_phase s") (* FIXME invert handshake_step *)
    apply auto
    done
next case (hs_get_roots_done s s') then show ?case
    apply -
    apply (drule_tac x=m in spec)
    apply (drule handshake_phase_invD)
    apply (force simp: hp_step_rel_def reachable_snapshot_inv_hs_get_roots_done)
    done
next case (hs_get_work_done s s') then show ?case
    apply (drule_tac x=m in spec)
    apply (drule handshake_phase_invD)
    apply (force simp add: hp_step_rel_def reachable_snapshot_inv_hs_get_work_done)
    done
qed

end

lemma (in mut_m') mutator_phase_inv[intro]:
  notes mut_m.mark_object_invL_def[inv]
  notes mut_m.handshake_invL_def[inv]
  notes fun_upd_apply[simp]
  shows
  " handshake_invL  mut_m.handshake_invL m'
        mut_m.mark_object_invL m'
        mut_get_roots.mark_object_invL m'
        mut_store_del.mark_object_invL m'
        mut_store_ins.mark_object_invL m'
        LSTP (fA_rel_inv  fM_rel_inv  handshake_phase_inv  mutators_phase_inv  valid_refs_inv) 
     mutator m'
    LSTP mutator_phase_inv "
proof( vcg_jackhammer (no_thin_post_inv)
    , simp_all add: mutator_phase_inv_aux_case split: hs_phase.splits
    , vcg_name_cases)
     case (alloc s s' rb) then show ?case
      apply -
      apply (clarsimp simp: fA_rel_inv_def fM_rel_inv_def white_def)
      apply (drule spec[where x=m])
      apply (intro conjI impI; clarsimp)
       apply (clarsimp simp: hp_step_rel_def simp: fA_rel_def fM_rel_def dest!: handshake_phase_invD)
       apply (elim disjE, auto; fail)
      apply (rule reachable_snapshot_inv_alloc, simp_all)
      apply (clarsimp simp: hp_step_rel_def simp: fA_rel_def fM_rel_def dest!: handshake_phase_invD)
      apply (cases "sys_ghost_hs_phase s"; clarsimp; blast)
      done
next case (hs_get_roots_done s s') then show ?case
      apply -
      apply (drule spec[where x=m])
      apply (simp add: no_black_refs_def reachable_snapshot_inv_def in_snapshot_def)
      done
next case (hs_get_work_done s s') then show ?case
      apply -
      apply (drule spec[where x=m])
      apply (clarsimp simp: no_black_refs_def reachable_snapshot_inv_def in_snapshot_def grey_protects_white_def)
      done
qed

(* FIXME Some of ‹mutator_phase_inv›, the rest in Global Noninterference *)

lemma no_black_refs_sweep_loop_free[simp]:
  "no_black_refs s  no_black_refs (s(sys := s sysheap := (sys_heap s)(gc_tmp_ref s := None)))"
unfolding no_black_refs_def by simp

lemma no_black_refs_load_W[simp]:
  " no_black_refs s; gc_W s = {} 
      no_black_refs (s(gc := s gcW := sys_W s, sys := s sysW := {}))"
unfolding no_black_refs_def by simp

lemma marked_insertions_sweep_loop_free[simp]:
  " mut_m.marked_insertions m s; white r s 
      mut_m.marked_insertions m (s(sys := (s sys)heap := (heap (s sys))(r := None)))"
unfolding mut_m.marked_insertions_def by (fastforce simp: fun_upd_apply split: mem_store_action.splits obj_at_splits option.splits)

lemma marked_deletions_sweep_loop_free[simp]:
  notes fun_upd_apply[simp]
  shows
  " mut_m.marked_deletions m s; mut_m.reachable_snapshot_inv m s; no_grey_refs s; white r s 
      mut_m.marked_deletions m (s(sys := s sysheap := (sys_heap s)(r := None)))"
unfolding mut_m.marked_deletions_def
apply (clarsimp split: mem_store_action.splits)
apply (rename_tac ref field option)
apply (drule_tac x="mw_Mutate ref field option" in spec)
apply (clarsimp simp: obj_at_field_on_heap_def split: option.splits)
 apply (rule conjI)
  apply (clarsimp simp: mut_m.reachable_snapshot_inv_def)
  apply (drule spec[where x=r], clarsimp simp: in_snapshot_def)
  apply (drule mp, auto simp: mut_m.reachable_def mut_m.tso_store_refs_def split: mem_store_action.splits)[1] (* FIXME rule *)
  apply (drule grey_protects_whiteD)
  apply (clarsimp simp: no_grey_refs_def)
 apply (clarsimp; fail)
apply (rule conjI; clarsimp)
apply (rule conjI)
 apply (clarsimp simp: mut_m.reachable_snapshot_inv_def)
 apply (drule spec[where x=r], clarsimp simp: in_snapshot_def)
 apply (drule mp, auto simp: mut_m.reachable_def mut_m.tso_store_refs_def split: mem_store_action.splits)[1] (* FIXME rule *)
 apply (drule grey_protects_whiteD)
 apply (clarsimp simp: no_grey_refs_def)
unfolding white_def apply (clarsimp split: obj_at_splits)
done

context gc
begin

lemma obj_fields_marked_inv_blacken:
  " gc_field_set s = {}; obj_fields_marked s; (gc_tmp_ref s points_to w) s; white w s   False"
by (simp add: obj_fields_marked_def obj_at_field_on_heap_def ran_def white_def split: option.splits obj_at_splits)

lemma obj_fields_marked_inv_has_white_path_to_blacken:
  " gc_field_set s = {}; gc_tmp_ref s  gc_W s; (gc_tmp_ref s has_white_path_to w) s; obj_fields_marked s; valid_W_inv s   w = gc_tmp_ref s"
by (metis (mono_tags, lifting) converse_rtranclpE gc.obj_fields_marked_inv_blacken has_white_path_to_def)

lemma mutator_phase_inv[intro]:
  notes fun_upd_apply[simp]
  shows
  " fM_fA_invL  gc_W_empty_invL  handshake_invL  obj_fields_marked_invL  sweep_loop_invL
        gc_mark.mark_object_invL
        LSTP (handshake_phase_inv  mutators_phase_inv  valid_refs_inv  valid_W_inv) 
     gc
    LSTP (mut_m.mutator_phase_inv m) "
proof( vcg_jackhammer (no_thin_post_inv)
     , simp_all add: mutator_phase_inv_aux_case white_def split: hs_phase.splits
     , vcg_name_cases )
     case (sweep_loop_free s s') then show ?case
       apply (intro allI conjI impI)
        apply (drule mut_m.handshake_phase_invD[where m=m], clarsimp simp: hp_step_rel_def; fail)
       apply (rule mut_m.reachable_snapshot_inv_sweep_loop_free, simp_all add: white_def)
       done
next case (mark_loop_get_work_load_W s s') then show ?case
      apply clarsimp
      apply (drule spec[where x=m])
      apply (clarsimp simp: mut_m.reachable_snapshot_inv_def in_snapshot_def grey_protects_white_def) (* FIXME rule *)
      done
next case (mark_loop_blacken s s') then show ?case
      apply -
      apply (drule spec[where x=m])
      apply clarsimp
      apply (intro allI conjI impI; clarsimp)
       apply (drule mut_m.handshake_phase_invD[where m=m], clarsimp simp: hp_step_rel_def)
      apply (clarsimp simp: mut_m.reachable_snapshot_inv_def in_snapshot_def grey_protects_white_def)
      apply (metis (no_types, opaque_lifting) obj_fields_marked_inv_has_white_path_to_blacken)
      done
next case (mark_loop_mo_co_mark s s' y) then show ?case by (clarsimp simp: handshake_in_syncD mut_m.reachable_snapshot_inv_mo_co_mark)
next case (mark_loop_get_roots_load_W s s') then show ?case
      apply clarsimp
      apply (drule spec[where x=m])
      apply (clarsimp simp: mut_m.reachable_snapshot_inv_def in_snapshot_def grey_protects_white_def) (* FIXME rule *)
      done
qed

end

lemma (in gc) strong_tricolour_inv[intro]:
  notes fun_upd_apply[simp]
  shows
  " fM_fA_invL  gc_W_empty_invL  gc_mark.mark_object_invL  obj_fields_marked_invL  sweep_loop_invL
        LSTP (strong_tricolour_inv  valid_W_inv) 
     gc
    LSTP strong_tricolour_inv "
unfolding strong_tricolour_inv_def
proof(vcg_jackhammer (no_thin_post_inv), vcg_name_cases)
  case (mark_loop_blacken s s' x xa) then show ?case by (fastforce elim!: obj_fields_marked_inv_blacken)
qed

lemma (in mut_m) strong_tricolour[intro]:
  notes fun_upd_apply[simp]
  shows
  " mark_object_invL
       mut_get_roots.mark_object_invL m
       mut_store_del.mark_object_invL m
       mut_store_ins.mark_object_invL m
       LSTP (fA_rel_inv  fM_rel_inv  handshake_phase_inv  mutators_phase_inv  strong_tricolour_inv  sys_phase_inv  valid_refs_inv) 
     mutator m
    LSTP strong_tricolour_inv "
unfolding strong_tricolour_inv_def
proof(vcg_jackhammer (no_thin_post_inv), vcg_name_cases)
  case (alloc s s' x xa rb) then show ?case
apply (clarsimp simp: fA_rel_inv_def fM_rel_inv_def)
apply (drule handshake_phase_invD)
apply (drule spec[where x=m])
apply (clarsimp simp: sys_phase_inv_aux_case
               split: hs_phase.splits if_splits)

 apply (blast dest: heap_colours_colours)

 (* FIXME rule? *)
 apply (metis (no_types, lifting) black_def no_black_refsD obj_at_cong option.simps(3))
 apply (metis (no_types, lifting) black_def no_black_refsD obj_at_cong option.distinct(1))

 apply (clarsimp simp: hp_step_rel_def)
 apply (elim disjE; force simp: fA_rel_def fM_rel_def split: obj_at_splits)

 apply (clarsimp simp: hp_step_rel_def)
 apply (elim disjE; force simp: fA_rel_def fM_rel_def split: obj_at_splits)
done
qed

(*<*)

end
(*>*)