Definition vis mu := fun b => locBlocksSrc mu b || frgnBlocksSrc mu b.
Inductive reach (m:mem) (B:block -> Prop): list (block * Z) -> block -> Prop :=
reach_nil: forall b, B b -> reach m B nil b
| reach_cons: forall b L b' z off n,
reach m B L b' ->
Mem.perm m b' z Cur Readable ->
ZMap.get z (PMap.get b' (Mem.mem_contents m)) =
Pointer b off n ->
reach m B ((b',z)::L) b.
Fixpoint reach' (m:mem) (B:block -> Prop) (L:list (block * Z)): block -> Prop:=
match L with
nil => B
| l::L => match l with
(b',z) => match ZMap.get z (PMap.get b' (Mem.mem_contents m))
with Pointer b off n => fun bb => bb = b /\
Mem.perm m b' z Cur Readable /\
reach' m B L b'
| _ => fun bb => False
end
end
end.
Fixpoint reach'' (m:mem) (B:block -> bool) (L:list (block * Z)): block -> bool:=
match L with
nil => B
| l::L => match l with
(b',z) => match ZMap.get z (PMap.get b' (Mem.mem_contents m))
with Pointer b off n => fun bb => eq_block bb b &&
Mem.perm_dec m b' z Cur Readable  &&
reach'' m B L b'
| _ => fun bb => false
end
end
end.
Parameter REACH : mem -> (block -> bool) -> block -> bool.
Definition replace_locals (mu:SM_Injection) pSrc' pTgt': SM_Injection :=
match mu with
Build_SM_Injection locBSrc locBTgt pSrc pTgt local extBSrc extBTgt fSrc fTgt extern =>
Build_SM_Injection locBSrc locBTgt pSrc' pTgt' local extBSrc extBTgt fSrc fTgt extern
end.
(*typically, we have forall b, pSrc b -> pSrc' b and forall b, pTgt b -> pTgt' b, i.e. only reclassify private entries as public*)
Definition replace_externs (mu:SM_Injection) fSrc' fTgt': SM_Injection :=
match mu with
Build_SM_Injection locBSrc locBTgt pSrc pTgt local extBSrc extBTgt fSrc fTgt extern =>
Build_SM_Injection locBSrc locBTgt pSrc pTgt local extBSrc extBTgt fSrc' fTgt' extern
end.
(*typically, we have forall b, fSrc b -> fSrc' b and forall b, fTgt b -> fTgt' b, i.e. only reclassify unknown entries as foreign*)
Definition getBlocks (V:list val) (b: block): bool :=
in_dec eq_block b
(fold_right (fun v L => match v with Vptr b' z => b'::L | _ => L end) nil V).
Definition REACH_closed m (X: Values.block -> bool) : Prop :=
(forall b, REACH m X b = true -> X b = true).
Definition mapped (j:meminj) b : bool :=
match j b with None => false | Some _ => true end.
(*The blocks explicitly exported via call arguments, plus the already shared blocks*)
Definition exportedSrc mu vals b := orb (getBlocks vals b) (sharedSrc mu b).
Definition exportedTgt mu vals b := orb (getBlocks vals b) (sharedTgt mu b).
Goal forall m1 mu (WD: SM_wd mu) vals b, pubBlocksSrc mu b = true ->
REACH m1 (exportedSrc mu vals) b = true.
Definition local_out_of_reach mu (m : mem) (b : block) (ofs : Z): Prop :=
locBlocksTgt mu b = true /\
forall b0 delta, local_of mu b0 = Some (b, delta) ->
(~ Mem.perm m b0 (ofs - delta) Max Nonempty \/
pubBlocksSrc mu b0 = false).
Definition genv2blocksBool {F V : Type} (ge : Genv.t F V):=
(fun b =>
match Genv.invert_symbol ge b with
Some id => true
| None => false
end,
fun b => match Genv.find_var_info ge b with
Some gv => true
| None => false
end).
Definition isGlobalBlock {F V : Type} (ge : Genv.t F V) :=
fun b => (fst (genv2blocksBool ge)) b || (snd (genv2blocksBool ge)) b.
Definition restrict_sm mu (X:block -> bool) :=
match mu with
Build_SM_Injection locBSrc locBTgt pSrc pTgt local extBSrc extBTgt fSrc fTgt extern =>
Build_SM_Injection locBSrc locBTgt pSrc pTgt (restrict local X)
extBSrc extBTgt fSrc fTgt (restrict extern X)
end.
Definition mkinitial_SM (mu: SM_Injection) frgnS frgnT :=
match mu with
Build_SM_Injection locBSrc locBTgt pSrc pTgt local extBSrc extBTgt fSrc fTgt extern =>
Build_SM_Injection (fun b => false) (fun b => false) (fun b => false) (fun b => false) (fun b => None)
(DomSrc mu) (DomTgt mu) frgnS frgnT (as_inj mu)
end.

Lemma mkinitial_SM_ok: forall {F1 V1 F2 V2:Type}
(g1: Genv.t F1 V1) (g2: Genv.t F2 V2) (G:genvs_domain_eq g1 g2)
mu (WD: SM_wd mu)
(PG: meminj_preserves_globals g1 (as_inj mu))
vals1 vals2 (VALS: Forall2 (val_inject (as_inj mu)) vals1 vals2)
m1 m2 (SMV: sm_valid mu m1 m2) (INJ: Mem.inject (as_inj mu) m1 m2)
(RchTgt: forall b, REACH m2 (fun b' => isGlobalBlock g2 b' || getBlocks vals2 b') b = true -> DomTgt mu b = true)
nu (NU: nu = mkinitial_SM mu
(REACH m1 (fun b => isGlobalBlock g1 b || getBlocks vals1 b))
(REACH m2 (fun b => isGlobalBlock g2 b || getBlocks vals2 b))),
SM_wd nu /\ sm_valid nu m1 m2 /\
meminj_preserves_globals g1 (extern_of nu) /\
(forall b, isGlobalBlock g1 b = true -> frgnBlocksSrc nu b = true) /\
REACH_closed m1 (vis nu) /\
REACH_closed m1 (mapped (as_inj nu)).