Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Definition target_accessible mu m tm args b ofs :=
Mem.valid_block tm b /\
(locBlocksTgt mu b=false ->
exists b0 d,
foreign_of mu b0 = Some (b, d)
/\ REACH m (getBlocks args) b0=true
/\ Mem.perm m b0 (ofs-d) Max Nonempty).
Definition incr mu mu' :=
inject_incr (as_inj mu) (as_inj mu')
/\ (forall b, DomSrc mu b=true -> DomSrc mu' b=true)
/\ (forall b, DomTgt mu b=true -> DomTgt mu' b=true).
Section open_semantics_preservation.
Variable (F V TF TV C D Z : Type) (z_init : Z).
Variable source : @EffectSem (Genv.t F V) C.
Variable target : @EffectSem (Genv.t TF TV) D.
Variable (geS : Genv.t F V) (geT : Genv.t TF TV).
Variable entry_points : list (val*val*signature).
Variable spec : ext_spec Z.
(* External function specifications P,Q,EXIT closed under injection of arguments, return values, and memories: *)
Variable spec_closed : ExtSpecProperties.closed spec.
(* External function specs commute w/ injection in the following sense: *)
Variable spec_ok :
forall ef x tys args targs m rty rv m' tm z z' j,
ext_spec_pre spec ef x tys args z m ->
ext_spec_post spec ef x rty rv z' m' ->
Mem.inject (as_inj j) m tm ->
val_list_inject (restrict (as_inj j) (vis j)) args targs ->
mem_forward m m' ->
Mem.unchanged_on (fun b ofs => REACH m (getBlocks args) b=false) m m' ->
exists j' rv' tm',
incr j j'
/\ oval_inject (as_inj j') rv rv'
/\ Mem.inject (as_inj j') m' tm'
/\ sm_inject_separated j j' m tm
/\ SM_wd j'
/\ sm_valid j' m' tm'
/\ mem_forward tm tm'
/\ Mem.unchanged_on (fun b ofs =>
~target_accessible j m tm args b ofs) tm tm'.
Variable sim : SM_simulation_inject source target geS geT entry_points.
Variable src_det : corestep_fun source.
Variable tgt_det : corestep_fun target.
Variable ext_spec_det : ExtSpecProperties.det spec.
Notation tr_source := (TraceSemantics.coopsem z_init source spec).
Notation tr_target := (TraceSemantics.coopsem z_init target spec).
(* Follow from determinism of ext calls + src/tgt_det above *)

Lemma REACH_as_inj': forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (getBlocks vals1) b1 = true)
B (HB: forall b b2 d, shared_of mu b = Some(b2,d) -> B b2 = true),
exists b2 d, as_inj mu b1 = Some (b2, d) /\
REACH m2 (fun b => orb (getBlocks vals2 b) (B b)) b2 = true.