Inductive structured_match_callstack mu (m: mem) (tm: mem):
                          callstack -> Values.block -> Values.block -> Prop :=
  | st_mcs_nil:
      forall hi bound tbound,
      match_globalenvs prog (restrict (as_inj mu) (vis mu)) hi ->
      Ple hi bound -> Ple hi tbound ->
      structured_match_callstack mu m tm nil bound tbound
  | st_mcs_cons:
      forall cenv tf e le te sp lo hi cs bound tbound
        (BOUND: Ple hi bound)
        (TBOUND: Plt sp tbound)
        (MTMP: match_temps (restrict (as_inj mu) (vis mu)) le te)
        (MENV: match_env (restrict (as_inj mu) (vis mu)) cenv e sp lo hi)
        (BOUND: match_bounds e m)
        (PERM: padding_freeable (restrict (as_inj mu) (vis mu)) e tm sp tf.(fn_stackspace))
        (SPlocal: locBlocksTgt mu sp = true) (*NEW*)

        (*LENB: Here is the condition me_incr from match_env above,
           but we assert it on the entire as_inj mu*)
        (ME_INCR: forall b tb delta,
               (as_inj mu) b = Some(tb, delta) -> Plt b lo -> Plt tb sp)
        (MCS: structured_match_callstack mu m tm cs lo sp),
      structured_match_callstack mu m tm (Frame cenv tf e le te sp lo hi :: cs) bound tbound.Inductive structured_match_callstack mu (m: mem) (tm: mem):
                          callstack -> Values.block -> Values.block -> Prop :=
  | st_mcs_nil:
      forall hi bound tbound,
      match_globalenvs prog (restrict (as_inj mu) (vis mu)) hi ->
      Ple hi bound -> Ple hi tbound ->
      structured_match_callstack mu m tm nil bound tbound
  | st_mcs_cons:
      forall cenv tf e le te sp lo hi cs bound tbound
        (BOUND: Ple hi bound)
        (TBOUND: Plt sp tbound)
        (MTMP: match_temps (restrict (as_inj mu) (vis mu)) le te)
        (MENV: match_env (restrict (as_inj mu) (vis mu)) cenv e sp lo hi)
        (BOUND: match_bounds e m)
        (PERM: padding_freeable (restrict (as_inj mu) (vis mu)) e tm sp tf.(fn_stackspace))
        (SPlocal: locBlocksTgt mu sp = true) (*NEW*)

        (*LENB: Here is the condition me_incr from match_env above,
           but we assert it on the entire as_inj mu*)
        (ME_INCR: forall b tb delta,
               (as_inj mu) b = Some(tb, delta) -> Plt b lo -> Plt tb sp)
        (MCS: structured_match_callstack mu m tm cs lo sp),
      structured_match_callstack mu m tm (Frame cenv tf e le te sp lo hi :: cs) bound tbound.Inductive structured_match_callstack mu (m: mem) (tm: mem):
                          callstack -> Values.block -> Values.block -> Prop :=
  | st_mcs_nil:
      forall hi bound tbound,
      match_globalenvs prog (restrict (as_inj mu) (vis mu)) hi ->
      Ple hi bound -> Ple hi tbound ->
      structured_match_callstack mu m tm nil bound tbound
  | st_mcs_cons:
      forall cenv tf e le te sp lo hi cs bound tbound
        (BOUND: Ple hi bound)
        (TBOUND: Plt sp tbound)
        (MTMP: match_temps (restrict (as_inj mu) (vis mu)) le te)
        (MENV: match_env (restrict (as_inj mu) (vis mu)) cenv e sp lo hi)
        (BOUND: match_bounds e m)
        (PERM: padding_freeable (restrict (as_inj mu) (vis mu)) e tm sp tf.(fn_stackspace))
        (SPlocal: locBlocksTgt mu sp = true) (*NEW*)

        (*LENB: Here is the condition me_incr from match_env above,
           but we assert it on the entire as_inj mu*)
        (ME_INCR: forall b tb delta,
               (as_inj mu) b = Some(tb, delta) -> Plt b lo -> Plt tb sp)
        (MCS: structured_match_callstack mu m tm cs lo sp),
      structured_match_callstack mu m tm (Frame cenv tf e le te sp lo hi :: cs) bound tbound.

(* Specifications: *)
Lemma structured_match_callstack_incr_bound: forall f m tm cs bound tbound bound' tbound', structured_match_callstack f m tm cs bound tbound -> Ple bound bound' -> Ple tbound tbound' -> structured_match_callstack f m tm cs bound' tbound'.
Lemma structured_match_callstack_intern_invariant: forall f1 m1 tm1 f2 m2 tm2 cs bound tbound (WD1: SM_wd f1) (WD2: SM_wd f2), intern_incr f1 f2 -> structured_match_callstack f1 m1 tm1 cs bound tbound -> (forall b ofs p, Plt b bound -> Mem.perm m2 b ofs Max p -> Mem.perm m1 b ofs Max p) -> (forall sp ofs, Plt sp tbound -> Mem.perm tm1 sp ofs Cur Freeable -> Mem.perm tm2 sp ofs Cur Freeable) -> (forall b, Plt b bound -> (as_inj f2) b = (as_inj f1) b) -> (forall b b' delta, (as_inj f2) b = Some(b', delta) -> Plt b' tbound -> (as_inj f1) b = Some(b', delta)) -> structured_match_callstack f2 m2 tm2 cs bound tbound.
Lemma structured_match_callstack_match_globalenvs: forall mu m tm cs bound tbound (MCS: structured_match_callstack mu m tm cs bound tbound), exists hi, Ple hi bound /\ Ple hi tbound /\ match_globalenvs prog (restrict (as_inj mu) (vis mu)) hi.
Lemma replace_locals_extern_incr_vis: forall mu nu pubS pubT (Hnu: nu = replace_locals mu pubS pubT) nu' (INC : extern_incr nu nu') (WDnu' : SM_wd nu') l m1' b (VIS: vis mu b = true), locBlocksSrc nu' b || DomSrc nu' b && (negb (locBlocksSrc nu' b) && REACH m1' (exportedSrc nu' l) b) = true.
Lemma structured_match_callstack_ext: forall mu m1 m2 cs bound tbound (MCS : structured_match_callstack mu m1 m2 cs bound tbound) m1' (FwdSrc : mem_forward m1 m1') nu vals1 vals2 (Hnu: nu = replace_locals mu (fun b0 : Values.block => locBlocksSrc mu b0 && REACH m1 (exportedSrc mu vals1) b0) (fun b0 : Values.block => locBlocksTgt mu b0 && REACH m2 (exportedTgt mu vals2) b0)) (SMvalMu : sm_valid mu m1 m2) (PG : meminj_preserves_globals (Genv.globalenv prog) (as_inj mu)) nu' (INC : extern_incr nu nu') (SEP : sm_inject_separated nu nu' m1 m2) (UNMAPPED : Mem.unchanged_on (fun (b : Values.block) (_ : Z) => locBlocksSrc nu b = true /\ pubBlocksSrc nu b = false) m1 m1') m2' (FwdTgt : mem_forward m2 m2') (OUTOFREACH : Mem.unchanged_on (local_out_of_reach nu m1) m2 m2') ret1 ret2 (WDnu' : SM_wd nu') (WDmu : SM_wd mu) (WDnu : SM_wd nu) (BND: Ple bound (Mem.nextblock m1)) (TBND:Ple tbound (Mem.nextblock m2)), structured_match_callstack (replace_externs nu' (fun b : Values.block => DomSrc nu' b && (negb (locBlocksSrc nu' b) && REACH m1' (exportedSrc nu' (ret1 :: nil)) b)) (fun b : Values.block => DomTgt nu' b && (negb (locBlocksTgt nu' b) && REACH m2' (exportedTgt nu' (ret2 :: nil)) b))) m1' m2' cs bound tbound.