Instance CompSpecs : compspecs. make_compspecs prog. Defined.
Definition Vprog : varspecs. mk_varspecs prog. Defined.
Local Open Scope Z.
Local Open Scope logic.
Definition object_invariant := list Z -> val -> mpred.
Definition tobject := tptr (Tstruct _object noattr).
Definition reset_spec (instance: object_invariant) :=
WITH self: val, history: list Z
PRE [ _self OF tobject]
PROP ()
LOCAL (temp _self self)
SEP (instance history self)
POST [ tvoid ]
PROP() LOCAL () SEP(instance nil self).
Definition twiddle_spec (instance: object_invariant) :=
WITH self: val, i: Z, history: list Z
PRE [ _self OF tobject, _i OF tint]
PROP (0 < i <= Int.max_signed / 4;
0 <= fold_right Z.add 0 history <= Int.max_signed / 4)
LOCAL (temp _self self; temp _i (Vint (Int.repr i)))
SEP (instance history self)
POST [ tint ]
EX v: Z,
PROP(2* fold_right Z.add 0 history < v <= 2* fold_right Z.add 0 (i::history))
LOCAL (temp ret_temp (Vint (Int.repr v)))
SEP(instance (i::history) self).
Definition object_methods (instance: object_invariant) (mtable: val) : mpred :=
EX sh: share, EX reset: val, EX twiddle: val,
!! readable_share sh &&
func_ptr' (reset_spec instance) reset *
func_ptr' (twiddle_spec instance) twiddle *
data_at sh (Tstruct _methods noattr) (reset,twiddle) mtable.
Hint Resolve object_methods_local_facts : saturate_local.
Definition object_mpred (history: list Z) (self: val) : mpred :=
EX instance: object_invariant, EX mtable: val,
(object_methods instance mtable *
field_at Ews (Tstruct _object noattr) [StructField _mtable] mtable self*
instance history self).
Definition foo_invariant : object_invariant :=
(fun (history: list Z) p =>
withspacer Ews (sizeof size_t + sizeof tint) (2 * sizeof size_t) (field_at Ews (Tstruct _foo_object noattr)
[StructField _data] (Vint (Int.repr (2*fold_right Z.add 0 history)))) p
*  malloc_token Ews (Tstruct _foo_object noattr) p).
Definition foo_reset_spec :=
DECLARE _foo_reset (reset_spec foo_invariant).
Definition foo_twiddle_spec :=
DECLARE _foo_twiddle  (twiddle_spec foo_invariant).
Definition make_foo_spec :=
DECLARE _make_foo
WITH gv: globals
PRE [ ]
PROP () LOCAL (gvars gv)
SEP (mem_mgr gv; object_methods foo_invariant (gv _foo_methods))
POST [ tobject ]
EX p: val, PROP () LOCAL (temp ret_temp p)
SEP (mem_mgr gv; object_mpred nil p; object_methods foo_invariant (gv _foo_methods)).
Definition main_spec :=
DECLARE _main
WITH gv: globals
PRE  [] main_pre prog tt nil gv
POST [ tint ]
EX i:Z, PROP(0<=i<=6) LOCAL (temp ret_temp (Vint (Int.repr i))) SEP(TT).
Definition Gprog : funspecs :=   ltac:(with_library prog [
foo_reset_spec; foo_twiddle_spec; make_foo_spec; main_spec]).
Ltac method_call witness hist' result :=
repeat apply seq_assoc1;
match goal with
|- semax _ (PROPx _ (LOCALx ?Q (SEPx ?R)))
(Ssequence (Sset ?mt (Efield (Ederef (Etempvar ?x _)  _) _ _))
_) _  =>
match Q with context [temp ?x ?x'] =>
match R with context [object_mpred _ x'] =>
let instance := fresh "instance" in let mtable := fresh "mtable" in
unfold object_mpred; Intros instance mtable;
forward;
unfold object_methods at 1;
let sh := fresh "sh" in let r := fresh "r" in let t := fresh "t" in
Intros sh r t;
forward;
forward_call witness;
[ .. | try Intros result;
sep_apply (make_object_methods sh instance r t mtable); [ auto .. | ];
sep_apply (object_mpred_i hist' x' instance mtable);
deadvars; try clear dependent sh; try clear r; try clear t
]
end end
end.

Lemma body_main:  semax_body Vprog Gprog f_main main_spec.