Require Arith.
Require PolyList.

Require machine.
Require axioms.
Require invar.
Require induction.
Require jsize.
Require lemmas.
Require java.

Section start.

Definition alloc_virtabs_mem : mem :=
  (fold_right
      [C:exp][m:mem](brute_alloc (size_of_virtab C) m (loc_of_virtab C))
      empty
      list_of_classes).

Definition start_mem : mem :=
  (fold_right
      [pair:exp*javatype][m:mem](updn (jsize_of (Snd pair)) 
          (brute_alloc (jsize_of (Snd pair)) m (Fst pair))
          (Fst pair) Null)
      alloc_virtabs_mem
      list_of_staticptrs).

Hints Resolve brute_alloc_addr brute_alloc_preserves addr_updn : temp.

Lemma addr_virtab_start_mem : (C:exp)
  (addr (size_of_virtab C) start_mem (loc_of_virtab C)).
Proof.
Intros.
Unfold start_mem.
Elim list_of_staticptrs.
  Simpl.
  Unfold alloc_virtabs_mem.
  Generalize (all_classes_in_list C); Intro.
  Decompose [and ex] H. 
  Rewrite H0.  
  Rewrite H3.
  Generalize H1; Clear H1.
  Clear H H0 H3.
  Elim list_of_classes. 
    Contradiction. 

    Intros.
    Simpl in H1.
    Decompose [or] H1.
      Rewrite H0.
      Simpl.
      EAuto with temp.

      Simpl.
      EAuto with temp.

  Intros.
  Simpl.
  EAuto with temp.
Qed.

Lemma addr_staticptr_start_mem_lemma : (E:exp)(T:javatype)
  (l:(list (exp*javatype)))
  (In (E,T) l) ->
  (addr (jsize_of T)
      (fold_right
      [pair:exp*javatype][m:mem](updn (jsize_of (Snd pair)) 
          (brute_alloc (jsize_of (Snd pair)) m (Fst pair))
          (Fst pair) Null)
      alloc_virtabs_mem
      l) E).
Proof.
Intros until l.
Elim l.
  Contradiction.

  Intros.
  Simpl in H0.
  Decompose [or] H0.
    Rewrite H1.  
    Simpl.
    EAuto with temp.

    Simpl.
    EAuto with temp.
Qed.


Lemma addr_staticptr_start_mem : (E:exp)(T:javatype)
  (given_staticptr E T) ->
  (SZ:nat)(jsize T SZ) ->
  (addr SZ start_mem E).
Proof.
Intros.
Rewrite (jsize_unique ? ? ? H0 (jsize_lemma T)).
Unfold start_mem.
Generalize (all_staticptrs_in_list E T H).
Elim list_of_staticptrs.
  Contradiction.

  Intros.  
  Simpl in H2.
  Decompose [or] H2.
    Rewrite H3.  
    Simpl.
    EAuto with temp.

    Simpl.
    EAuto with temp.
Qed.

  
Lemma double_or_lemma : (A,B,C,D:Prop)
  A\/B ->
  A\/C ->
  (A->D)->
  (B->C->D)->
   D.
Proof.
Tauto.
Qed.

Hints Resolve apart_sym : temp.

Lemma null_staticptr_start_mem : (E:exp)(T:javatype)
  (given_staticptr E T) ->
  (SZ:nat)(jsize T SZ) ->
  (seln SZ start_mem E)=Null.
Proof.
Intros.
Rewrite (jsize_unique ? ? ? H0 (jsize_lemma T)).
Unfold start_mem.
Generalize (all_staticptrs_in_list E T H).
Generalize (list_all_staticptrs).
Elim list_of_staticptrs.
  Contradiction.

  Intros. 
  NewDestruct a.
  Assert E=e/\T=j\/(apart E (jsize_of T) e (jsize_of j)).
    EApply staticptr_equal_or_apart; Try Prolog [jsize_lemma] 1.
    EApply H2; Simpl; Auto.
  Simpl in H3.
  EApply double_or_lemma.
    EExact H4.

    Decompose [or] H3.
      Injection H5; Auto.    
 
      Right; EExact H5.

    Intros (eq1,eq2). 
    Rewrite eq1; Rewrite eq2.
    Simpl.
    EApply updn_seln.    
    EAuto with temp.

    Intros.
    Simpl.
    Rewrite updn_seln_apart; EAuto with temp.
    Fold (jsize_of T).
    Fold (jsize_of j).
    Rewrite <- brute_alloc_alias.
      EApply H1; EAuto.
      Intros.
      EApply H2.
      Simpl.
      Auto.

      EApply addr_staticptr_start_mem_lemma.   
      Assumption.
Qed.

Definition start_state : state' :=
  (mkstate'
      (mkstate Null Null start_mem (nil ?))
      nilrep
      start_mem).


Hint ofType : axioms := Constructors ofType.
Hint ptr : axioms := Constructors ptr.
Hint ofmem : axioms := Constructors ofmem.
Hint jsize : axioms := Constructors jsize.


Definition start_ofType [e:exp][t:type] :=
   ((C:exp)(t=(jvirtab C) -> False)) /\
  ((e=Null) \/ (EX s:javasimpletype | t=s) \/ (t=jclassdesc)).
  
Definition start_ptr [e:exp][r:rorw][t:type] :=
    (EX s:javatype | r=rw /\ t=s /\ (given_staticptr e s)).

Definition start_ofmem [m:mem] :=
  ((e:exp)(r:rorw)(t:type)(sz:nat)
  (jsize t sz) ->
  (start_ptr e r t) ->
  (start_ofType (seln sz m e) t)) /\ 
  ((e:exp)(r:rorw)(t:type)(sz:nat)
  (jsize t sz) ->
  (start_ptr e r t) ->
  (addr sz m e)).


Lemma start_state_preds : 
  (
    (e:exp; t:type)(ofType start_state e t)->
    (start_ofType e t)    
  ) /\ (
    (e:exp; r:rorw; t:type)(ptr start_state e r t)->
    (start_ptr e r t)
  ) /\ (
    (m:mem)(ofmem start_state m)->
    (start_ofmem m)
  ).
Proof.
Apply ofType_ptr_ofmem_simul_ind;
  Unfold start_ofmem start_ofType start_ptr;
  Try (Split; [Solve [Intros; Discriminate_something] | EAuto with axioms]);
  Intros; EAuto with axioms.
  
  Decompose [and or] H1; Auto; Try Discriminate_something.
  Decompose [ex] H3; Discriminate_something.

  Decompose [and or] H0; Auto; Try Discriminate_something.
  Decompose [ex] H2; Discriminate_something.

  Decompose [and] H3.
  Unfold sel4.
  EAuto.

  Decompose [and] H3.
  Unfold sel8.
  EAuto.

  Contradiction.

  Contradiction.

(* ptr cases *)
  Decompose [and or] H0; Try Discriminate_something.  
    Rewrite H4 in H1; Inversion H1 using nonnull_null_inv.
    
    Decompose [ex] H3; Discriminate_something.

  Decompose [and] H0.  
  ElimType False; EAuto.

  Decompose [and or] H1; Try Discriminate_something.
    Rewrite H5 in H2; Inversion H2 using nonnull_null_inv.
    
    Decompose [ex] H4; Discriminate_something.

  Decompose [and] H1.
  ElimType False; EAuto.

  Decompose [and or] H0; Try Discriminate_something.
    Rewrite H4 in H1; Inversion H1 using nonnull_null_inv.

    Decompose [ex] H3; Discriminate_something.

  Decompose [and or] H0; Try Discriminate_something.
    Rewrite H8 in H3; Inversion H3 using nonnull_null_inv.

    Decompose [ex] H7; Discriminate_something.

  Decompose [and or] H0; Try Discriminate_something.
    Rewrite H4 in H1; Inversion H1 using nonnull_null_inv.

    Decompose [ex] H3; Discriminate_something.

  Contradiction.
  
(* ofmem cases *)
  Decompose [and] H5; Clear H5.
  Split; Intros.
    Decompose [and ex] H8.
    Rewrite H9; Rewrite H9 in H5.
    Decompose [and ex] H0.
    Rewrite H11 in H1.
    Unfold upd4.
    Elim (staticptr_equal_or_apart e ADDR x x0 sz (4)); Auto.
      Intros (eq1,eq2).
      Rewrite eq1.  
      Rewrite <-eq2 in H1.
      Rewrite (jsize_unique ? ? ? H5 H1).   
      Rewrite updn_seln.
        Rewrite eq2; Rewrite <- H11.
        Assumption.

        EApply H7; EAuto.
        Rewrite H9 in H8; Rewrite eq1 in H8.
        EAuto.

      Intros.
      Rewrite updn_seln_apart; EAuto with temp.
      Unfold upd4.
      EApply addr_updn; EAuto.

(* similarly for (8) *)
  Decompose [and] H5; Clear H5.
  Split; Intros.
    Decompose [and ex] H8.
    Rewrite H9; Rewrite H9 in H5.
    Decompose [and ex] H0.
    Rewrite H11 in H1.
    Unfold upd8.
    Elim (staticptr_equal_or_apart e ADDR x x0 sz (8)); Auto.
      Intros (eq1,eq2).
      Rewrite eq1.  
      Rewrite <-eq2 in H1.
      Rewrite (jsize_unique ? ? ? H5 H1).   
      Rewrite updn_seln.
        Rewrite eq2; Rewrite <- H11.
        Assumption.

        EApply H7; EAuto.
        Rewrite H9 in H8; Rewrite eq1 in H8.
        EAuto.

      Intros.
      Rewrite updn_seln_apart; EAuto with temp.
      Unfold upd8.
      EApply addr_updn; EAuto.

(* Now last_alloc *)
  Unfold last_alloc_of start_state.
  Split; Intros.
    Decompose [ex and] H0.
    Split; Intros.
      Rewrite H1 in H3; Discriminate H3.

      Left.
      Rewrite H1 in H.
      EApply null_staticptr_start_mem; EAuto.

    Decompose [ex and] H0.
    Rewrite H1 in H.
    EApply addr_staticptr_start_mem; EAuto.
Qed.

Lemma start_state_ptr : 
    (e:exp; r:rorw; t:type)(ptr start_state e r t)->
    (start_ptr e r t).
Proof.
EApply proj1.
EApply proj2.
EExact start_state_preds.
Qed.

Lemma invariant_start_state : (invariant start_state).
Proof.
Unfold_invar_Goal; Intros.
  Assert H1 := (start_state_ptr ? ? ? H0).    
  Unfold start_ptr in H1.
  Decompose [ex and] H1.
  Rewrite H2 in H.
  EApply addr_staticptr_start_mem; EAuto.
  
  Assert H3 := (start_state_ptr ? ? ? H).    
  Unfold start_ptr in H3.
  Decompose [ex and] H3.
  Assert H8 := (start_state_ptr ? ? ? H1).    
  Unfold start_ptr in H8.
  Decompose [ex and] H8.
  Rewrite H4 in H0.
  Rewrite H6 in H2. 
  Elim (staticptr_equal_or_apart ? ? ? ? ? ? H7 H0 H11 H2); EAuto.
  Intros (eq1,eq2).
  Left. 
  Repeat Split; Auto.
  Rewrite H4.   
  Rewrite H6.
  Rewrite eq2.
  Reflexivity. 

  EApply addr_virtab_start_mem; EAuto.
  Assert H1 := (start_state_ptr ? ? ? H).    
  Unfold start_ptr in H1.
  Decompose [ex and] H1.
  Rewrite H2 in H0.
  EApply staticptr_virtab_apart; EAuto.

  Replace (mem_of' start_state) with (last_alloc_of start_state);
      [Idtac | Reflexivity].
  Constructor.
Qed.

End start.
