Theory JVMCFG_wf

theory JVMCFG_wf imports JVMInterpretation "../StaticInter/CFGExit_wf" begin

inductive_set Def :: "wf_jvmprog ⇒ cfg_node ⇒ var set"
  for P :: "wf_jvmprog"
  and n :: "cfg_node"
where
  Def_Main_Heap:
  "n = (ClassMain P, MethodMain P, ⌊0⌋, Return)
  ⟹ Heap ∈ Def P n"
| Def_Main_Exception:
  "n = (ClassMain P, MethodMain P, ⌊0⌋, Return)
  ⟹ Exception ∈ Def P n"
| Def_Main_Stack_0:
  "n = (ClassMain P, MethodMain P, ⌊0⌋, Return)
  ⟹ Stack 0 ∈ Def P n"
| Def_Load:
  "⟦ n = (C, M, ⌊pc⌋, Enter);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = Load idx;
  i = stkLength (P, C, M) pc⟧
  ⟹ Stack i ∈ Def P n"
| Def_Store:
  "⟦ n = (C, M, ⌊pc⌋, Enter);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = Store idx ⟧
  ⟹ Local idx ∈ Def P n"
| Def_Push:
  "⟦ n = (C, M, ⌊pc⌋, Enter);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = Push v;
  i = stkLength (P, C, M) pc ⟧
  ⟹ Stack i ∈ Def P n"
| Def_IAdd:
  "⟦ n = (C, M, ⌊pc⌋, Enter);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = IAdd;
  i = stkLength (P, C, M) pc - 2 ⟧
  ⟹ Stack i ∈ Def P n"
| Def_CmpEq:
  "⟦ n = (C, M, ⌊pc⌋, Enter);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = CmpEq;
  i = stkLength (P, C, M) pc - 2 ⟧
  ⟹ Stack i ∈ Def P n"
| Def_New_Heap:
  "⟦ n = (C, M, ⌊pc⌋, Normal);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = New Cl ⟧
  ⟹ Heap ∈ Def P n"
| Def_New_Stack:
  "⟦ n = (C, M, ⌊pc⌋, Normal);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = New Cl;
  i = stkLength (P, C, M) pc ⟧
  ⟹ Stack i ∈ Def P n"
| Def_Exception:
  "⟦ n = (C, M, ⌊pc⌋, Exceptional pco nt);
  C ≠ ClassMain P ⟧
  ⟹ Exception ∈ Def P n"
| Def_Exception_handle:
  "⟦ n = (C, M, ⌊pc⌋, Exceptional ⌊pc'⌋ Enter);
  C ≠ ClassMain P;
  i = stkLength (P, C, M) pc' - 1 ⟧
  ⟹ Stack i ∈ Def P n"
| Def_Exception_handle_return:
  "⟦ n = (C, M, ⌊pc⌋, Exceptional ⌊pc'⌋ Return);
  C ≠ ClassMain P;
  i = stkLength (P, C, M) pc' - 1 ⟧
  ⟹ Stack i ∈ Def P n"
| Def_Getfield:
  "⟦ n = (C, M, ⌊pc⌋, Normal);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = Getfield Cl Fd;
  i = stkLength (P, C, M) pc - 1 ⟧
  ⟹ Stack i ∈ Def P n"
| Def_Putfield:
  "⟦ n = (C, M, ⌊pc⌋, Normal);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = Putfield Cl Fd ⟧
  ⟹ Heap ∈ Def P n"
| Def_Invoke_Return_Heap:
  "⟦ n = (C, M, ⌊pc⌋, Return);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = Invoke M' n' ⟧
  ⟹ Heap ∈ Def P n"
| Def_Invoke_Return_Exception:
  "⟦ n = (C, M, ⌊pc⌋, Return);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = Invoke M' n' ⟧
  ⟹ Exception ∈ Def P n"
| Def_Invoke_Return_Stack:
  "⟦ n = (C, M, ⌊pc⌋, Return);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = Invoke M' n';
  i = stkLength (P, C, M) (Suc pc) - 1 ⟧
  ⟹ Stack i ∈ Def P n"
| Def_Invoke_Call_Heap:
  "⟦ n = (C, M, None, Enter);
  C ≠ ClassMain P ⟧
  ⟹ Heap ∈ Def P n"
| Def_Invoke_Call_Local:
  "⟦ n = (C, M, None, Enter);
  C ≠ ClassMain P;
  i < locLength (P, C, M) 0 ⟧
  ⟹ Local i ∈ Def P n"
| Def_Return:
  "⟦ n = (C, M, ⌊pc⌋, Enter);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = instr.Return ⟧
  ⟹ Stack 0 ∈ Def P n"

inductive_set Use :: "wf_jvmprog ⇒ cfg_node ⇒ var set"
  for P :: "wf_jvmprog"
  and n :: "cfg_node"
where
  Use_Main_Heap:
  "n = (ClassMain P, MethodMain P, ⌊0⌋, Normal)
  ⟹ Heap ∈ Use P n"
| Use_Load:
  "⟦ n = (C, M, ⌊pc⌋, Enter);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = Load idx ⟧
  ⟹ Local idx ∈ Use P n"
| Use_Enter_Stack:
  "⟦ n = (C, M, ⌊pc⌋, Enter);
  C ≠ ClassMain P;
  case (instrs_of (PROG P) C M ! pc)
    of Store n' ⇒ d = 1
    | Getfield F Cl ⇒ d = 1
    | Putfield F Cl ⇒ d = 2
    | Checkcast Cl ⇒ d = 1
    | Invoke M' n' ⇒ d = Suc n'
    | IAdd ⇒ d ∈ {1, 2}
    | IfFalse i ⇒ d = 1
    | CmpEq ⇒ d ∈ {1 , 2}
    | Throw ⇒ d = 1
    | instr.Return ⇒ d = 1
    | _ ⇒ False;
  i = stkLength (P, C, M) pc - d ⟧
  ⟹ Stack i ∈ Use P n"
| Use_Enter_Local:
  "⟦ n = (C, M, ⌊pc⌋, Enter);
  C ≠ ClassMain P;
  instrs_of (PROG P) C M ! pc = Load n' ⟧
  ⟹ Local n' ∈ Use P n"
| Use_Enter_Heap:
  "⟦ n = (C, M, ⌊pc⌋, Enter);
  C ≠ ClassMain P;
  case (instrs_of (PROG P) C M ! pc)
    of New Cl ⇒ True
    | Checkcast Cl ⇒ True
    | Throw ⇒ True
    | _ ⇒ False ⟧
  ⟹ Heap ∈ Use P n"
| Use_Normal_Heap:
  "⟦ n = (C, M, ⌊pc⌋, Normal);
  C ≠ ClassMain P;
  case (instrs_of (PROG P) C M ! pc)
    of New Cl ⇒ True
    | Getfield F Cl ⇒ True
    | Putfield F Cl ⇒ True
    | Invoke M' n' ⇒ True
    | _ ⇒ False ⟧
  ⟹ Heap ∈ Use P n"
| Use_Normal_Stack:
  "⟦ n = (C, M, ⌊pc⌋, Normal);
  C ≠ ClassMain P;
  case (instrs_of (PROG P) C M ! pc)
    of Getfield F Cl ⇒ d = 1
    | Putfield F Cl ⇒ d ∈ {1, 2}
    | Invoke M' n' ⇒ d > 0 ∧ d ≤ Suc n'
    | _ ⇒ False;
  i = stkLength (P, C, M) pc - d ⟧
  ⟹ Stack i ∈ Use P n"
| Use_Return_Heap:
  "⟦ n = (C, M, ⌊pc⌋, Return);
  instrs_of (PROG P) C M ! pc = Invoke M' n' ∨ C = ClassMain P ⟧
  ⟹ Heap ∈ Use P n"
| Use_Return_Stack:
  "⟦ n = (C, M, ⌊pc⌋, Return);
  (instrs_of (PROG P) C M ! pc = Invoke M' n' ∧ i = stkLength (P, C, M) (Suc pc) - 1) ∨
  (C = ClassMain P ∧ i = 0) ⟧
  ⟹ Stack i ∈ Use P n"
| Use_Return_Exception:
  "⟦ n = (C, M, ⌊pc⌋, Return);
  instrs_of (PROG P) C M ! pc = Invoke M' n' ∨ C = ClassMain P ⟧
  ⟹ Exception ∈ Use P n"
| Use_Exceptional_Stack:
  "⟦ n = (C, M, ⌊pc⌋, Exceptional opc' nt);
  case (instrs_of (PROG P) C M ! pc)
    of Throw ⇒ True
    | _ ⇒ False;
  i = stkLength (P, C, M) pc - 1 ⟧
  ⟹ Stack i ∈ Use P n"
| Use_Exceptional_Exception:
  "⟦ n = (C, M, ⌊pc⌋, Exceptional ⌊pc'⌋ Return);
  instrs_of (PROG P) C M ! pc = Invoke M' n' ⟧
  ⟹ Exception ∈ Use P n"
| Use_Method_Leave_Exception:
  "⟦ n = (C, M, None, Return);
  C ≠ ClassMain P ⟧
  ⟹ Exception ∈ Use P n"
| Use_Method_Leave_Heap:
  "⟦ n = (C, M, None, Return);
  C ≠ ClassMain P ⟧
  ⟹ Heap ∈ Use P n"
| Use_Method_Leave_Stack:
  "⟦ n = (C, M, None, Return);
  C ≠ ClassMain P ⟧
  ⟹ Stack 0 ∈ Use P n"
| Use_Method_Entry_Heap:
  "⟦ n = (C, M, None, Enter);
  C ≠ ClassMain P ⟧
  ⟹ Heap ∈ Use P n"
| Use_Method_Entry_Local:
  "⟦ n = (C, M, None, Enter);
  C ≠ ClassMain P;
  i < locLength (P, C, M) 0 ⟧
  ⟹ Local i ∈ Use P n"

fun ParamDefs :: "wf_jvmprog ⇒ cfg_node ⇒ var list"
where
  "ParamDefs P (C, M, ⌊pc⌋, Return) = [Heap, Stack (stkLength (P, C, M) (Suc pc) - 1), Exception]"
  | "ParamDefs P (C, M, opc, nt) = []"

function ParamUses :: "wf_jvmprog ⇒ cfg_node ⇒ var set list"
where
  "ParamUses P (ClassMain P, MethodMain P, ⌊0⌋, Normal) = [{Heap},{}]"
  |
  "M ≠ MethodMain P ∨ opc ≠ ⌊0⌋ ∨ nt ≠ Normal
  ⟹ ParamUses P (ClassMain P, M, opc, nt) = []"
  |
  "C ≠ ClassMain P
  ⟹ ParamUses P (C, M, opc, nt) = (case opc of None ⇒ []
  | ⌊pc⌋ ⇒ (case nt of Normal ⇒ (case (instrs_of (PROG P) C M ! pc) of
      Invoke M' n ⇒ (
          {Heap} # rev (map (λn. {Stack (stkLength (P, C, M) pc - (Suc n))}) [0..<n + 1])
      )
      | _ ⇒ [])
    | _ ⇒ []
    )
  )"
  by atomize_elim auto
termination by lexicographic_order

lemma in_set_ParamDefsE:
  "⟦ V ∈ set (ParamDefs P n);
  ⋀C M pc. ⟦ n = (C, M, ⌊pc⌋, Return);
         V ∈ {Heap, Stack (stkLength (P, C, M) (Suc pc) - 1), Exception} ⟧ ⟹ thesis ⟧
  ⟹ thesis"
  by (cases "(P, n)" rule: ParamDefs.cases) auto

lemma in_set_ParamUsesE:
  assumes V_in_ParamUses: "V ∈ ⋃(set (ParamUses P n))"
  obtains "n = (ClassMain P, MethodMain P, ⌊0⌋, Normal)" and "V = Heap"
  | C M pc M' n' i where "n = (C, M, ⌊pc⌋, Normal)" and "instrs_of (PROG P) C M ! pc = Invoke M' n'"
    and "V = Heap ∨ V = Stack (stkLength (P, C, M) pc - Suc i)" and "i < Suc n'" and "C ≠ ClassMain P"
proof (cases "(P, n)" rule: ParamUses.cases)
  case 1 with V_in_ParamUses that show ?thesis by clarsimp
next
  case 2 with V_in_ParamUses that show ?thesis by clarsimp
next
  case (3 C P M pc nt)
  with V_in_ParamUses that show ?thesis
    using [[simproc del: list_to_set_comprehension]]
    by (cases nt, auto) (rename_tac a b, case_tac "instrs_of (PROG P) C M ! a", simp_all, fastforce)
qed

lemma sees_method_fun_wf:
  assumes "PROG P ⊢ D sees M': Ts→T = (mxs, mxl0, is, xt) in D"
  and "(D, D', fs, ms) ∈ set (PROG P)"
  and "(M', Ts', T', mxs', mxl0', is', xt') ∈ set ms"
  shows "Ts = Ts' ∧ T = T' ∧ mxs = mxs' ∧ mxl0 = mxl0' ∧ is = is' ∧ xt = xt'"
proof -
  from distinct_class_names [of P] ‹(D, D', fs, ms) ∈ set (PROG P)›
  have "class (PROG P) D = ⌊(D', fs, ms)⌋"
    by (fastforce intro: map_of_SomeI simp: class_def)
  moreover with distinct_method_names have "distinct_fst ms"
    by fastforce
  ultimately show ?thesis using
    ‹PROG P ⊢ D sees M': Ts→T = (mxs, mxl0, is, xt) in D›
    ‹(M', Ts', T', mxs', mxl0', is', xt') ∈ set ms›
    by (fastforce dest: visible_method_exists map_of_SomeD distinct_fst_isin_same_fst
      simp: distinct_fst_is_distinct_fst)
qed

interpretation JVMCFG_wf:
  CFG_wf  "sourcenode" "targetnode" "kind" "valid_edge (P, C0, Main)"
  "(ClassMain P, MethodMain P, None, Enter)"
  "(λ(C, M, pc, type). (C, M))" "get_return_edges P"
  "((ClassMain P, MethodMain P),[],[]) # procs (PROG P)"
  "(ClassMain P, MethodMain P)"
  "Def P" "Use P" "ParamDefs P" "ParamUses P"
  for P C0 Main
proof (unfold_locales)
  show "Def P (ClassMain P, MethodMain P, None, Enter) = {} ∧
    Use P (ClassMain P, MethodMain P, None, Enter) = {}"
    by (fastforce elim: Def.cases Use.cases)
next
  fix a Q r p fs ins outs
  assume "valid_edge (P, C0, Main) a"
    and "kind a = Q:r↪⇘p⇙fs"
    and params: "(p, ins, outs) ∈ set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
  hence "(P, C0, Main) ⊢ sourcenode a -Q:r↪⇘p⇙fs→ targetnode a"
    by (simp add: valid_edge_def)
  from this params show "length (ParamUses P (sourcenode a)) = length ins"
  proof cases
    case Main_Call
    with params show ?thesis
      by auto (erule in_set_procsE, auto dest: sees_method_idemp sees_method_fun)
  next
    case (CFG_Invoke_Call C M pc M' n ST LT D' Ts T mxs mxl0 "is" xt D Q' paramDefs)
    hence [simp]: "Q' = Q" and [simp]: "r = (C, M, pc)" and [simp]: "p = (D, M')"
      and [simp]: "fs = paramDefs"
      by simp_all
    from CFG_Invoke_Call obtain T' mxs' mpc' xt' where
      "PROG P,T',mxs',mpc',xt' ⊢ instrs_of (PROG P) C M ! pc,pc :: TYPING P C M"
      by (blast dest: reachable_node_impl_wt_instr)
    moreover from ‹PROG P ⊢ D' sees M': Ts→T = (mxs, mxl0, is, xt) in D›
    have "PROG P ⊢ D sees M': Ts→T = (mxs, mxl0, is, xt) in D"
      by -(drule sees_method_idemp)
    with params have "PROG P ⊢ D sees M': Ts→T=(mxs, mxl0, is, xt) in D"
      and "ins = Heap # map Local [0..<Suc (length Ts)]"
      by (fastforce elim: in_set_procsE dest: sees_method_fun)+
    ultimately show ?thesis using CFG_Invoke_Call
      by (fastforce dest: sees_method_fun list_all2_lengthD simp: min_def)
  qed simp_all
next
  fix a
  assume "valid_edge (P, C0, Main) a"
  thus "distinct (ParamDefs P (targetnode a))"
    by (clarsimp simp: valid_edge_def) (erule JVMCFG.cases, auto)
next
  fix a Q' p f' ins outs
  assume "valid_edge (P, C0, Main) a"
    and "kind a = Q'↩⇘p⇙f'"
    and params: "(p, ins, outs) ∈ set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
  hence "(P, C0, Main) ⊢ sourcenode a -Q'↩⇘p⇙f'→ targetnode a"
    by (simp add: valid_edge_def)
  from this params
  show "length (ParamDefs P (targetnode a)) = length outs"
    by cases (auto elim: in_set_procsE)
next
  fix n V
  assume params: "V ∈ set (ParamDefs P n)"
    and vn: "CFG.valid_node sourcenode targetnode (valid_edge (P, C0, Main)) n"
  then obtain ek n'
    where ve:"valid_edge (P, C0, Main) (n, ek, n') ∨ valid_edge (P, C0, Main) (n', ek, n)"
    by (fastforce simp: JVMCFG_Interpret.valid_node_def)
  from params obtain C M pc where [simp]: "n = (C, M, ⌊pc⌋, Return)"
    and V: "V ∈ {Heap, Stack (stkLength (P, C, M) (Suc pc) - 1), Exception}"
    by (blast elim: in_set_ParamDefsE)
  from ve show "V ∈ Def P n"
  proof
    assume "valid_edge (P, C0, Main) (n, ek, n')"
    thus ?thesis unfolding valid_edge_def
    proof cases
      case Main_Return_to_Exit with V show ?thesis
        by (auto intro: Def_Main_Heap Def_Main_Stack_0 Def_Main_Exception simp: stkLength_def)
    next
      case CFG_Invoke_Return_Check_Normal with V show ?thesis
        by (fastforce intro: Def_Invoke_Return_Heap
          Def_Invoke_Return_Stack Def_Invoke_Return_Exception)
    next
      case CFG_Invoke_Return_Check_Exceptional with V show ?thesis
        by (fastforce intro: Def_Invoke_Return_Heap
          Def_Invoke_Return_Stack Def_Invoke_Return_Exception)
    next
      case CFG_Invoke_Return_Exceptional_prop with V show ?thesis
        by (fastforce intro: Def_Invoke_Return_Heap
          Def_Invoke_Return_Stack Def_Invoke_Return_Exception)
    qed simp_all
  next
    assume "valid_edge (P, C0, Main) (n', ek, n)"
    thus ?thesis unfolding valid_edge_def
    proof cases
      case Main_Call_LFalse with V show ?thesis
        by (auto intro: Def_Main_Heap Def_Main_Stack_0 Def_Main_Exception simp: stkLength_def)
    next
      case CFG_Invoke_False with V show ?thesis
        by (fastforce intro: Def_Invoke_Return_Heap
          Def_Invoke_Return_Stack Def_Invoke_Return_Exception)
    next
      case CFG_Return_from_Method with V show ?thesis
        by (fastforce elim!: JVMCFG.cases intro!: Def_Main_Stack_0
          intro: Def_Main_Heap Def_Main_Exception Def_Invoke_Return_Heap
          Def_Invoke_Return_Exception Def_Invoke_Return_Stack simp: stkLength_def)
    qed simp_all
  qed
next
  fix a Q r p fs ins outs V
  assume ve: "valid_edge (P, C0, Main) a"
    and kind: "kind a = Q:r↪⇘p⇙fs"
    and params: "(p, ins, outs) ∈ set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
    and V: "V ∈ set ins"
  from params V obtain D fs ms Ts T mb where "class (PROG P) (fst p) = ⌊(D, fs, ms)⌋"
    and "method": "PROG P ⊢ (fst p) sees (snd p): Ts→T = mb in (fst p)"
    and ins: "ins = Heap # map Local [0..<Suc (length Ts)]"
    by (cases p) (fastforce elim: in_set_procsE)
  from ve kind show "V ∈ Def P (targetnode a)" unfolding valid_edge_def
  proof cases
    case (Main_Call T' mxs mxl0 "is" xt D' initParams)
    with kind have "PROG P ⊢ D' sees Main: []→T' = (mxs, mxl0, is, xt) in D'"
      and [simp]: "p = (D', Main)"
      by (auto dest: sees_method_idemp)
    with "method" have [simp]: "Ts = []" and [simp]: "T' = T" and [simp]: "mb = (mxs, mxl0, is, xt)"
      by (fastforce dest: sees_method_fun)+
    from Main_Call ins V show ?thesis
      by (fastforce intro!: Def_Invoke_Call_Heap Def_Invoke_Call_Local
        dest: sees_method_idemp wt_jvm_prog_impl_wt_start[OF wf_jvmprog_is_wf_typ]
        simp: locLength_def wt_start_def)
  next
    case (CFG_Invoke_Call C M pc M' n ST LT D' Ts' T' mxs mxl0 "is" xt D'')
    with kind have "PROG P ⊢ D'' sees M': Ts'→T' = (mxs, mxl0, is, xt) in D''"
      and [simp]: "p = (D'', M')"
      by (auto dest: sees_method_idemp)
    with "method" have [simp]: "Ts' = Ts" and [simp]: "T' = T" and [simp]: "mb = (mxs, mxl0, is, xt)"
      by (fastforce dest: sees_method_fun)+
    from CFG_Invoke_Call ins V show ?thesis
      by (fastforce intro!: Def_Invoke_Call_Local Def_Invoke_Call_Heap
        dest: sees_method_idemp wt_jvm_prog_impl_wt_start[OF wf_jvmprog_is_wf_typ] list_all2_lengthD
        simp: locLength_def min_def wt_start_def)
  qed simp_all
next
  fix a Q r p fs
  assume "valid_edge (P, C0, Main) a" and "kind a = Q:r↪⇘p⇙fs"
  thus "Def P (sourcenode a) = {}" unfolding valid_edge_def
    by cases (auto elim: Def.cases)
next
  fix n V
  assume "CFG.valid_node sourcenode targetnode (valid_edge (P, C0, Main)) n"
    and V: "V ∈ ⋃(set (ParamUses P n))"
  then obtain ek n'
    where ve:"valid_edge (P, C0, Main) (n, ek, n') ∨ valid_edge (P, C0, Main) (n', ek, n)"
    by (fastforce simp: JVMCFG_Interpret.valid_node_def)
  from V obtain C M pc M' n'' i where
    V: "n = (ClassMain P, MethodMain P, ⌊0⌋, Normal) ∧ V = Heap ∨
    n = (C, M, ⌊pc⌋, Normal) ∧ instrs_of (PROG P) C M ! pc = Invoke M' n'' ∧
      (V = Heap ∨ V = Stack (stkLength (P, C, M) pc - Suc i)) ∧ i < Suc n'' ∧ C ≠ ClassMain P"
    by -(erule in_set_ParamUsesE, fastforce+)
  from ve show "V ∈ Use P n"
  proof
    assume "valid_edge (P, C0, Main) (n, ek, n')"
    from this V show ?thesis unfolding valid_edge_def
    proof cases
      case Main_Call_LFalse with V show ?thesis by (fastforce intro: Use_Main_Heap)
    next
      case Main_Call with V show ?thesis by (fastforce intro: Use_Main_Heap)
    next
      case CFG_Invoke_Call with V show ?thesis
        by (fastforce intro: Use_Normal_Heap Use_Normal_Stack [where d="Suc i"])
    next
      case CFG_Invoke_False with V show ?thesis
        by (fastforce intro: Use_Normal_Heap Use_Normal_Stack [where d="Suc i"])
    qed simp_all
  next
    assume "valid_edge (P, C0, Main) (n', ek, n)"
    from this V show ?thesis unfolding valid_edge_def
    proof cases
      case Main_to_Call with V show ?thesis by (fastforce intro: Use_Main_Heap)
    next
      case CFG_Invoke_Check_NP_Normal with V show ?thesis
        by (fastforce intro: Use_Normal_Heap Use_Normal_Stack [where d="Suc i"])
    qed simp_all
  qed
next
  fix a Q p f ins outs V
  assume "valid_edge (P, C0, Main) a"
    and "kind a = Q↩⇘p⇙f"
    and "(p, ins, outs) ∈ set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
    and "V ∈ set outs"
  thus "V ∈ Use P (sourcenode a)" unfolding valid_edge_def
    by (cases, simp_all)
  (fastforce elim: in_set_procsE
    intro: Use_Method_Leave_Heap Use_Method_Leave_Stack Use_Method_Leave_Exception)
next
  fix a V s
  assume ve: "valid_edge (P, C0, Main) a"
    and V_notin_Def: "V ∉ Def P (sourcenode a)"
    and ik: "intra_kind (kind a)"
    and pred: "JVMCFG_Interpret.pred (kind a) s"
  show "JVMCFG_Interpret.state_val
    (CFG.transfer (((ClassMain P, MethodMain P), [], []) # procs (PROG P)) (kind a) s) V
    = JVMCFG_Interpret.state_val s V"
  proof (cases s)
    case Nil
    thus ?thesis by simp
  next
    case [simp]: Cons
    with ve V_notin_Def ik pred show ?thesis unfolding valid_edge_def
    proof cases
      case CFG_Load with V_notin_Def show ?thesis by (fastforce intro: Def_Load)
    next case CFG_Store with V_notin_Def show ?thesis by (fastforce intro: Def_Store)
    next case CFG_Push with V_notin_Def show ?thesis by (fastforce intro: Def_Push)
    next case CFG_IAdd with V_notin_Def show ?thesis by (fastforce intro: Def_IAdd)
    next case CFG_CmpEq with V_notin_Def show ?thesis by (fastforce intro: Def_CmpEq)
    next case CFG_New_Update with V_notin_Def show ?thesis
        by (fastforce intro: Def_New_Heap Def_New_Stack)
    next case CFG_New_Exceptional_prop with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception)
    next case CFG_New_Exceptional_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Getfield_Update with V_notin_Def show ?thesis
        by (fastforce intro: Def_Getfield split: prod.split)
    next case CFG_Getfield_Exceptional_prop with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception)
    next case CFG_Getfield_Exceptional_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Putfield_Update with V_notin_Def show ?thesis
        by (fastforce intro: Def_Putfield split: prod.split)
    next case CFG_Putfield_Exceptional_prop with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception)
    next case CFG_Putfield_Exceptional_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Checkcast_Exceptional_prop with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception)
    next case CFG_Checkcast_Exceptional_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Throw_prop with V_notin_Def show ?thesis by (fastforce intro: Def_Exception)
    next case CFG_Throw_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Invoke_NP_prop with V_notin_Def show ?thesis by (fastforce intro: Def_Exception)
    next case CFG_Invoke_NP_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Invoke_Return_Exceptional_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception_handle_return Def_Exception)
    next case CFG_Return with V_notin_Def show ?thesis by (fastforce intro: Def_Return)
    qed (simp_all add: intra_kind_def)
  qed
next
  fix a s s'
  assume ve: "valid_edge (P, C0, Main) a"
    and use_Eq: "∀V∈Use P (sourcenode a). JVMCFG_Interpret.state_val s V
    = JVMCFG_Interpret.state_val s' V"
    and ik: "intra_kind (kind a)"
    and pred_s: "JVMCFG_Interpret.pred (kind a) s"
    and pred_s': "JVMCFG_Interpret.pred (kind a) s'"
  then obtain cfs C M pc cs cfs' C' M' pc' cs' where [simp]: "s = (cfs, (C, M, pc)) # cs"
    and [simp]: "s' = (cfs', (C', M', pc')) # cs'"
    by (cases s, fastforce) (cases s', fastforce+)
  from ve show "∀V∈Def P (sourcenode a).
             JVMCFG_Interpret.state_val
              (CFG.transfer (((ClassMain P, MethodMain P), [], []) # procs (PROG P)) (kind a) s) V =
             JVMCFG_Interpret.state_val
              (CFG.transfer (((ClassMain P, MethodMain P), [], []) # procs (PROG P)) (kind a) s') V"
    unfolding valid_edge_def
  proof cases
    case Main_Call with ik show ?thesis by (simp add: intra_kind_def)
  next case Main_Return_to_Exit with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Return_Heap Use_Return_Exception Use_Return_Stack)
  next case Method_LFalse with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Method_Entry_Heap Use_Method_Entry_Local) 
  next case Method_LTrue with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Method_Entry_Heap Use_Method_Entry_Local)
  next case CFG_Load with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Enter_Local)
  next case CFG_Store with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Enter_Stack)
  next case (CFG_IAdd C M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      and "Stack (stkLength (P, C, M) pc - 2) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)+
    with use_Eq CFG_IAdd show ?thesis by (auto elim!: Def.cases)
  next case (CFG_CmpEq C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      and "Stack (stkLength (P, C, M) pc - 2) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)+
    with use_Eq CFG_CmpEq show ?thesis by (auto elim!: Def.cases)
  next case CFG_New_Update
    hence "Heap ∈ Use P (sourcenode a)" by (fastforce intro: Use_Normal_Heap)
    with use_Eq CFG_New_Update show ?thesis by (fastforce elim: Def.cases)
  next case (CFG_Getfield_Update C  M pc)
    hence "Heap ∈ Use P (sourcenode a)"
      and "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Normal_Heap Use_Normal_Stack)+
    with use_Eq CFG_Getfield_Update show ?thesis by (auto elim!: Def.cases split: prod.split)
  next case (CFG_Putfield_Update C  M pc)
    hence "Heap ∈ Use P (sourcenode a)"
      and "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      and "Stack (stkLength (P, C, M) pc - 2) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Normal_Heap Use_Normal_Stack)+
    with use_Eq CFG_Putfield_Update show ?thesis by (auto elim!: Def.cases split: prod.split)
  next case (CFG_Throw_prop C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Exceptional_Stack)
    with use_Eq CFG_Throw_prop show ?thesis by (fastforce elim: Def.cases)
  next case (CFG_Throw_handle C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Exceptional_Stack)
    with use_Eq CFG_Throw_handle show ?thesis by (fastforce elim: Def.cases)
  next case CFG_Invoke_Call with ik show ?thesis by (simp add: intra_kind_def)
  next case CFG_Invoke_Return_Check_Normal with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Return_Heap Use_Return_Exception Use_Return_Stack)
  next case CFG_Invoke_Return_Check_Exceptional with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Return_Heap Use_Return_Exception Use_Return_Stack)
  next case CFG_Invoke_Return_Exceptional_handle with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Exceptional_Exception)
  next case CFG_Invoke_Return_Exceptional_prop with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Return_Heap Use_Return_Exception Use_Return_Stack)
  next case CFG_Return with use_Eq show ?thesis
      by (fastforce elim!: Def.cases intro: Use_Enter_Stack)
  next case CFG_Return_from_Method with ik show ?thesis by (simp add: intra_kind_def)
  qed (fastforce elim: Def.cases)+
next
  fix a s s'
  assume ve: "valid_edge (P, C0, Main) a"
    and pred: "JVMCFG_Interpret.pred (kind a) s"
    and "snd (hd s) = snd (hd s')"
    and use_Eq: "∀V∈Use P (sourcenode a).
           JVMCFG_Interpret.state_val s V = JVMCFG_Interpret.state_val s' V"
    and "length s = length s'"
  then obtain cfs C M pc cs cfs' cs' where [simp]: "s = (cfs, (C, M, pc)) # cs"
    and [simp]: "s' = (cfs', (C, M, pc)) # cs'" and length_cs: "length cs = length cs'"
    by (cases s, fastforce) (cases s', fastforce+)
  from ve pred show "JVMCFG_Interpret.pred (kind a) s'"
    unfolding valid_edge_def
  proof cases
    case Main_Call_LFalse with pred show ?thesis by simp
  next case Main_Call with pred use_Eq show ?thesis by simp
  next case Method_LTrue with pred use_Eq show ?thesis by simp
  next case CFG_Goto with pred use_Eq show ?thesis by simp
  next case (CFG_IfFalse_False C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with use_Eq CFG_IfFalse_False pred show ?thesis by fastforce
  next case (CFG_IfFalse_True C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_IfFalse_True show ?thesis by fastforce
  next case CFG_New_Check_Normal
    hence "Heap ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Heap)
    with pred use_Eq CFG_New_Check_Normal show ?thesis by fastforce
  next case CFG_New_Check_Exceptional 
    hence "Heap ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Heap)
    with pred use_Eq CFG_New_Check_Exceptional show ?thesis by fastforce
  next case (CFG_Getfield_Check_Normal C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Getfield_Check_Normal show ?thesis by fastforce
  next case (CFG_Getfield_Check_Exceptional C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Getfield_Check_Exceptional  show ?thesis by fastforce
  next case (CFG_Putfield_Check_Normal C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 2) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Putfield_Check_Normal show ?thesis by fastforce
  next case (CFG_Putfield_Check_Exceptional C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 2) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Putfield_Check_Exceptional show ?thesis by fastforce
  next case (CFG_Checkcast_Check_Normal C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      and "Heap ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack Use_Enter_Heap)+
    with pred use_Eq CFG_Checkcast_Check_Normal show ?thesis by fastforce
  next case (CFG_Checkcast_Check_Exceptional C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      and "Heap ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack Use_Enter_Heap)+
    with pred use_Eq CFG_Checkcast_Check_Exceptional show ?thesis by fastforce
  next case (CFG_Throw_Check C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) ∈ Use P (sourcenode a)"
      and "Heap ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack Use_Enter_Heap)+
    with pred use_Eq CFG_Throw_Check show ?thesis by fastforce
  next case (CFG_Invoke_Check_NP_Normal C  M pc M' n)
    hence "Stack (stkLength (P, C, M) pc - (Suc n)) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Invoke_Check_NP_Normal show ?thesis by fastforce
  next case (CFG_Invoke_Check_NP_Exceptional C  M pc M' n)
    hence "Stack (stkLength (P, C, M) pc - (Suc n)) ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Invoke_Check_NP_Exceptional show ?thesis by fastforce
  next case (CFG_Invoke_Call C  M pc M' n)
    hence "Stack (stkLength (P, C, M) pc - (Suc n)) ∈ Use P (sourcenode a)"
      and "Heap ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Normal_Heap Use_Normal_Stack)+
    with pred use_Eq CFG_Invoke_Call show ?thesis by fastforce
  next case CFG_Invoke_Return_Check_Normal
    hence "Exception ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Return_Exception)
    with pred use_Eq CFG_Invoke_Return_Check_Normal show ?thesis by fastforce
  next case CFG_Invoke_Return_Check_Exceptional
    hence "Exception ∈ Use P (sourcenode a)" and "Heap ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Return_Exception Use_Return_Heap)+
    with pred use_Eq CFG_Invoke_Return_Check_Exceptional show ?thesis by fastforce
  next case CFG_Invoke_Return_Exceptional_prop
    hence "Exception ∈ Use P (sourcenode a)" and "Heap ∈ Use P (sourcenode a)"
      by (fastforce intro: Use_Return_Exception Use_Return_Heap)+
    with pred use_Eq CFG_Invoke_Return_Exceptional_prop show ?thesis by fastforce
  next case CFG_Return_from_Method with pred length_cs show ?thesis by clarsimp
  qed auto
next
  fix a Q r p fs ins outs
  assume "valid_edge (P, C0, Main) a"
    and kind: "kind a = Q:r↪⇘p⇙fs"
    and params: "(p, ins, outs) ∈ set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
  thus "length fs = length ins" unfolding valid_edge_def
  proof cases
    case (Main_Call  T mxs mxl0 "is" xt D)
    with kind params have [simp]: "p = (D, Main)"
      and "PROG P ⊢ D sees Main: []→T = (mxs, mxl0, is, xt) in D"
      and "ins = Heap # map Local [0..<Suc 0]"
      by (auto elim!: in_set_procsE dest: sees_method_fun sees_method_idemp)
    with Main_Call kind show ?thesis
      by auto
  next
    case (CFG_Invoke_Call C  M pc M' n ST LT D' Ts T mxs mxl0 "is" xt D)
    with kind params have [simp]: "p = (D, M')"
      and "PROG P ⊢ D' sees M': Ts→T = (mxs, mxl0, is, xt) in D"
      and "ins = Heap # map Local [0..<Suc (length Ts)]"
      by (auto elim!: in_set_procsE dest: sees_method_fun sees_method_idemp)
    moreover with ‹(P, C0, Main) ⊢ ⇒(C, M, ⌊pc⌋, Normal)› ‹C ≠ ClassMain P›
      ‹instrs_of (PROG P) C M ! pc = Invoke M' n› ‹TYPING P C M ! pc = ⌊(ST, LT)⌋›
      ‹ST ! n = Class D'› have "n = length Ts"
      by (fastforce dest!: reachable_node_impl_wt_instr dest: sees_method_fun list_all2_lengthD)
    ultimately show ?thesis using CFG_Invoke_Call kind by auto
  qed simp_all
next
  fix a Q r p fs a' Q' r' p' fs' s s'
  assume ve_a: "valid_edge (P, C0, Main) a"
    and kind_a: "kind a = Q:r↪⇘p⇙fs"
    and ve_a': "valid_edge (P, C0, Main) a'"
    and kind_a': "kind a' = Q':r'↪⇘p'⇙fs'"
    and src: "sourcenode a = sourcenode a'"
    and pred_s: "JVMCFG_Interpret.pred (kind a) s"
    and pred_s': "JVMCFG_Interpret.pred (kind a') s"
  then obtain cfs C M pc cs cfs' C' M' pc' cs' 
    where [simp]: "s = (cfs, (C, M, pc)) # cs" 
    by (cases s) fastforce+
  with ve_a kind_a show "a = a'" unfolding valid_edge_def
  proof cases
    case Main_Call with ve_a' kind_a' src pred_s pred_s' show ?thesis unfolding valid_edge_def
      by (cases a, cases a') (fastforce elim: JVMCFG.cases dest: sees_method_fun)
  next
    case CFG_Invoke_Call
    note invoke_call1 = this
    from ve_a' kind_a' show ?thesis unfolding valid_edge_def
    proof cases
      case Main_Call with CFG_Invoke_Call src have False by simp
      thus ?thesis by simp
    next
      case CFG_Invoke_Call with src invoke_call1 show ?thesis
        by clarsimp (cases a, cases a', fastforce dest: sees_method_fun)
    qed simp_all
  qed simp_all
next
  fix a Q r p fs i ins outs s s'
  assume ve: "valid_edge (P, C0, Main) a"
    and kind: "kind a = Q:r↪⇘p⇙fs"
    and "i < length ins"
    and "(p, ins, outs) ∈ set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
    and "JVMCFG_Interpret.pred (kind a) s"
    and "JVMCFG_Interpret.pred (kind a) s'"
    and use_Eq: "∀V∈ParamUses P (sourcenode a) ! i.
           JVMCFG_Interpret.state_val s V = JVMCFG_Interpret.state_val s' V"
  then obtain cfs C M pc cs cfs' C' M' pc' cs' where [simp]: "s = (cfs, (C, M, pc)) # cs"
    and [simp]: "s' = (cfs', (C', M', pc')) # cs'"
    by (cases s, fastforce) (cases s', fastforce+)
  from ve kind
  show "JVMCFG_Interpret.params fs (JVMCFG_Interpret.state_val s) ! i =
          JVMCFG_Interpret.params fs (JVMCFG_Interpret.state_val s') ! i"
    unfolding valid_edge_def
  proof cases
    case Main_Call with kind use_Eq ‹i < length ins› show ?thesis
      by (cases i) auto
  next
    case CFG_Invoke_Call
    { fix P C M pc n st st' i
      have "∀V∈rev (map (λn. {Stack (stkLength (P, C, M) pc - Suc n)}) [0..<n]) ! i. st V = st' V
        ⟹ JVMCFG_Interpret.params
        (rev (map (λi s. s (Stack (stkLength (P, C, M) pc - Suc i))) [0..<n])) st ! i =
        JVMCFG_Interpret.params
        (rev (map (λi s. s (Stack (stkLength (P, C, M) pc - Suc i))) [0..<n])) st' ! i"
        by (induct n arbitrary: i) (simp, case_tac i, auto)
    }
    note stack_params = this
    from CFG_Invoke_Call kind use_Eq ‹i < length ins› show ?thesis
      by (cases i, auto) (case_tac nat, auto intro: stack_params)
  qed simp_all
next
  fix a Q' p f' ins outs vmap vmap'
  assume "valid_edge (P, C0, Main) a"
    and "kind a = Q'↩⇘p⇙f'"
    and "(p, ins, outs) ∈ set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
  thus "f' vmap vmap' = vmap'(ParamDefs P (targetnode a) [:=] map vmap outs)"
    unfolding valid_edge_def
    by (cases, simp_all) (fastforce elim: in_set_procsE simp: fun_upd_twist)
next
  fix a a'
  { fix P n f n' e n''
    assume "P ⊢ n -⇑f→ n'" and "P ⊢ n -e→ n''"
    hence "e = ⇑f ∧ n' = n''"
      by cases (simp_all, (fastforce elim: JVMCFG.cases)+)
  }
  note upd_det = this
  { fix P n Q n' Q' n'' s
    assume "P ⊢ n -(Q)√→ n'" and edge': "P ⊢ n -(Q')√→ n''" and trg: "n' ≠ n''"
    hence "(Q s ⟶ ¬ Q' s) ∧ (Q' s ⟶ ¬ Q s)"
    proof cases
      case CFG_Throw_Check with edge' trg show ?thesis by cases fastforce+
    qed (simp_all, (fastforce elim: JVMCFG.cases)+)
  }
  note pred_det = this
  assume "valid_edge (P, C0, Main) a"
    and ve': "valid_edge (P, C0, Main) a'"
    and src: "sourcenode a = sourcenode a'"
    and trg: "targetnode a ≠ targetnode a'"
    and "intra_kind (kind a)"
    and "intra_kind (kind a')"
  thus "∃Q Q'. kind a = (Q)√ ∧ kind a' = (Q')√ ∧ (∀s. (Q s ⟶ ¬ Q' s) ∧ (Q' s ⟶ ¬ Q s))"
    unfolding valid_edge_def intra_kind_def
    by (auto dest: upd_det pred_det)
qed

interpretation JVMCFGExit_wf :
  CFGExit_wf "sourcenode" "targetnode" "kind" "valid_edge (P, C0, Main)"
  "(ClassMain P, MethodMain P, None, Enter)"
  "(λ(C, M, pc, type). (C, M))" "get_return_edges P"
  "((ClassMain P, MethodMain P),[],[]) # procs (PROG P)"
  "(ClassMain P, MethodMain P)"
  "(ClassMain P, MethodMain P, None, Return)"
  "Def P" "Use P" "ParamDefs P" "ParamUses P"
proof
  show "Def P (ClassMain P, MethodMain P, None, nodeType.Return) = {} ∧
    Use P (ClassMain P, MethodMain P, None, nodeType.Return) = {}"
    by (fastforce elim: Def.cases Use.cases)
qed

end