You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
6.7 KiB
286 lines
6.7 KiB
9 years ago
|
(*
|
||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* This source code is licensed under the BSD style license found in the
|
||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||
|
*)
|
||
|
|
||
8 years ago
|
open! IStd
|
||
9 years ago
|
|
||
9 years ago
|
module F = Format
|
||
|
|
||
9 years ago
|
module type S = sig
|
||
9 years ago
|
type astate
|
||
|
|
||
9 years ago
|
val (<=) : lhs:astate -> rhs:astate -> bool (* fst \sqsubseteq snd? *)
|
||
9 years ago
|
val join : astate -> astate -> astate
|
||
9 years ago
|
val widen : prev:astate -> next:astate -> num_iters:int -> astate
|
||
9 years ago
|
val pp : F.formatter -> astate -> unit
|
||
|
end
|
||
|
|
||
8 years ago
|
module type WithBottom = sig
|
||
|
include S
|
||
|
|
||
|
val empty : astate
|
||
|
end
|
||
|
|
||
8 years ago
|
module type WithTop = sig
|
||
|
include S
|
||
|
|
||
|
val top : astate
|
||
|
end
|
||
|
|
||
9 years ago
|
module BottomLifted (Domain : S) = struct
|
||
9 years ago
|
type astate =
|
||
9 years ago
|
| Bottom
|
||
9 years ago
|
| NonBottom of Domain.astate
|
||
9 years ago
|
|
||
8 years ago
|
let empty = Bottom
|
||
9 years ago
|
|
||
9 years ago
|
let (<=) ~lhs ~rhs =
|
||
8 years ago
|
if phys_equal lhs rhs
|
||
9 years ago
|
then true
|
||
|
else
|
||
|
match lhs, rhs with
|
||
|
| Bottom, _ -> true
|
||
|
| _ , Bottom -> false
|
||
|
| NonBottom lhs, NonBottom rhs -> Domain.(<=) ~lhs ~rhs
|
||
9 years ago
|
|
||
|
let join astate1 astate2 =
|
||
8 years ago
|
if phys_equal astate1 astate2
|
||
9 years ago
|
then astate1
|
||
|
else
|
||
|
match astate1, astate2 with
|
||
|
| Bottom, _ -> astate2
|
||
|
| _, Bottom -> astate1
|
||
|
| NonBottom a1, NonBottom a2 -> NonBottom (Domain.join a1 a2)
|
||
9 years ago
|
|
||
9 years ago
|
let widen ~prev ~next ~num_iters =
|
||
8 years ago
|
if phys_equal prev next
|
||
9 years ago
|
then prev
|
||
|
else
|
||
|
match prev, next with
|
||
|
| Bottom, _ -> next
|
||
|
| _, Bottom -> prev
|
||
|
| NonBottom prev, NonBottom next -> NonBottom (Domain.widen ~prev ~next ~num_iters)
|
||
9 years ago
|
|
||
|
let pp fmt = function
|
||
9 years ago
|
| Bottom -> F.fprintf fmt "_|_"
|
||
9 years ago
|
| NonBottom astate -> Domain.pp fmt astate
|
||
9 years ago
|
end
|
||
9 years ago
|
|
||
8 years ago
|
module TopLifted (Domain: S) = struct
|
||
|
type astate =
|
||
|
| Top
|
||
|
| NonTop of Domain.astate
|
||
|
|
||
|
let top = Top
|
||
|
|
||
|
let (<=) ~lhs ~rhs =
|
||
|
if phys_equal lhs rhs
|
||
|
then true
|
||
|
else
|
||
|
match lhs, rhs with
|
||
|
| _, Top -> true
|
||
|
| Top, _ -> false
|
||
|
| NonTop lhs, NonTop rhs -> Domain.(<=) ~lhs ~rhs
|
||
|
|
||
|
let join astate1 astate2 =
|
||
|
if phys_equal astate1 astate2
|
||
|
then astate1
|
||
|
else
|
||
|
match astate1, astate2 with
|
||
|
| Top, _
|
||
|
| _, Top -> Top
|
||
|
| NonTop a1, NonTop a2 -> NonTop (Domain.join a1 a2)
|
||
|
|
||
|
let widen ~prev ~next ~num_iters =
|
||
|
if phys_equal prev next
|
||
|
then prev
|
||
|
else
|
||
|
match prev, next with
|
||
|
| Top, _
|
||
|
| _, Top -> Top
|
||
|
| NonTop prev, NonTop next -> NonTop (Domain.widen ~prev ~next ~num_iters)
|
||
|
|
||
|
let pp fmt = function
|
||
|
| Top -> F.fprintf fmt "T"
|
||
|
| NonTop astate -> Domain.pp fmt astate
|
||
|
|
||
|
end
|
||
|
|
||
9 years ago
|
module Pair (Domain1 : S) (Domain2 : S) = struct
|
||
|
type astate = Domain1.astate * Domain2.astate
|
||
|
|
||
|
let (<=) ~lhs ~rhs =
|
||
8 years ago
|
if phys_equal lhs rhs
|
||
9 years ago
|
then true
|
||
|
else
|
||
9 years ago
|
Domain1.(<=) ~lhs:(fst lhs) ~rhs:(fst rhs) && Domain2.(<=) ~lhs:(snd lhs) ~rhs:(snd rhs)
|
||
9 years ago
|
|
||
|
let join astate1 astate2 =
|
||
8 years ago
|
if phys_equal astate1 astate2
|
||
9 years ago
|
then astate1
|
||
9 years ago
|
else Domain1.join (fst astate1) (fst astate2), Domain2.join (snd astate1) (snd astate2)
|
||
9 years ago
|
|
||
9 years ago
|
let widen ~prev ~next ~num_iters =
|
||
8 years ago
|
if phys_equal prev next
|
||
9 years ago
|
then prev
|
||
|
else
|
||
|
Domain1.widen ~prev:(fst prev) ~next:(fst next) ~num_iters,
|
||
|
Domain2.widen ~prev:(snd prev) ~next:(snd next) ~num_iters
|
||
9 years ago
|
|
||
|
let pp fmt (astate1, astate2) =
|
||
|
F.fprintf fmt "(%a, %a)" Domain1.pp astate1 Domain2.pp astate2
|
||
|
end
|
||
|
|
||
8 years ago
|
module FiniteSet (Element : PrettyPrintable.PrintableOrderedType) = struct
|
||
|
include PrettyPrintable.MakePPSet(Element)
|
||
9 years ago
|
type astate = t
|
||
|
|
||
9 years ago
|
let (<=) ~lhs ~rhs =
|
||
8 years ago
|
if phys_equal lhs rhs
|
||
9 years ago
|
then true
|
||
|
else subset lhs rhs
|
||
|
|
||
|
let join astate1 astate2 =
|
||
8 years ago
|
if phys_equal astate1 astate2
|
||
9 years ago
|
then astate1
|
||
|
else union astate1 astate2
|
||
|
|
||
|
let widen ~prev ~next ~num_iters:_ =
|
||
|
join prev next
|
||
9 years ago
|
end
|
||
9 years ago
|
|
||
8 years ago
|
module InvertedSet (S : PrettyPrintable.PPSet) = struct
|
||
|
include S
|
||
|
type astate = t
|
||
|
|
||
|
let (<=) ~lhs ~rhs =
|
||
|
if phys_equal lhs rhs
|
||
|
then true
|
||
|
else subset rhs lhs
|
||
|
|
||
|
let join astate1 astate2 =
|
||
|
if phys_equal astate1 astate2
|
||
|
then astate1
|
||
|
else inter astate1 astate2
|
||
|
|
||
|
let widen ~prev ~next ~num_iters:_ =
|
||
|
join prev next
|
||
|
end
|
||
|
|
||
8 years ago
|
module Map (Key : PrettyPrintable.PrintableOrderedType) (ValueDomain : S) = struct
|
||
|
module M = PrettyPrintable.MakePPMap(Key)
|
||
9 years ago
|
include M
|
||
|
type astate = ValueDomain.astate M.t
|
||
|
|
||
|
(** true if all keys in [lhs] are in [rhs], and each lhs value <= corresponding rhs value *)
|
||
|
let (<=) ~lhs ~rhs =
|
||
8 years ago
|
if phys_equal lhs rhs
|
||
9 years ago
|
then true
|
||
|
else
|
||
|
M.for_all
|
||
|
(fun k lhs_v ->
|
||
|
try ValueDomain.(<=) ~lhs:lhs_v ~rhs:(M.find k rhs)
|
||
|
with Not_found -> false)
|
||
|
lhs
|
||
|
|
||
|
let join astate1 astate2 =
|
||
8 years ago
|
if phys_equal astate1 astate2
|
||
9 years ago
|
then astate1
|
||
|
else
|
||
|
M.merge
|
||
|
(fun _ v1_opt v2_opt -> match v1_opt, v2_opt with
|
||
|
| Some v1, Some v2 -> Some (ValueDomain.join v1 v2)
|
||
|
| Some v, _ | _, Some v -> Some v
|
||
|
| None, None -> None)
|
||
|
astate1
|
||
|
astate2
|
||
|
|
||
8 years ago
|
let widen ~prev ~next ~num_iters =
|
||
|
if phys_equal prev next
|
||
|
then prev
|
||
|
else
|
||
|
M.merge
|
||
|
(fun _ v1_opt v2_opt -> match v1_opt, v2_opt with
|
||
|
| Some v1, Some v2 -> Some (ValueDomain.widen ~prev:v1 ~next:v2 ~num_iters)
|
||
|
| Some v, _ | _, Some v -> Some v
|
||
|
| None, None -> None)
|
||
8 years ago
|
prev
|
||
|
next
|
||
9 years ago
|
|
||
|
let pp fmt astate =
|
||
|
M.pp ~pp_value:ValueDomain.pp fmt astate
|
||
|
end
|
||
8 years ago
|
|
||
8 years ago
|
module InvertedMap (M : PrettyPrintable.PPMap) (ValueDomain : S) = struct
|
||
|
include M
|
||
|
type astate = ValueDomain.astate M.t
|
||
|
|
||
|
let (<=) ~lhs ~rhs =
|
||
|
if phys_equal lhs rhs
|
||
|
then true
|
||
|
else
|
||
|
try M.for_all (fun k rhs_v -> ValueDomain.(<=) ~lhs:(M.find k lhs) ~rhs:rhs_v) rhs
|
||
|
with Not_found -> false
|
||
|
|
||
|
let join astate1 astate2 =
|
||
|
if phys_equal astate1 astate2
|
||
|
then astate1
|
||
|
else
|
||
|
M.merge
|
||
|
(fun _ v1_opt v2_opt -> match v1_opt, v2_opt with
|
||
|
| Some v1, Some v2 -> Some (ValueDomain.join v1 v2)
|
||
|
| _ -> None)
|
||
|
astate1
|
||
|
astate2
|
||
|
|
||
|
let widen ~prev ~next ~num_iters =
|
||
|
if phys_equal prev next
|
||
|
then prev
|
||
|
else
|
||
|
M.merge
|
||
|
(fun _ v1_opt v2_opt -> match v1_opt, v2_opt with
|
||
|
| Some v1, Some v2 -> Some (ValueDomain.widen ~prev:v1 ~next:v2 ~num_iters)
|
||
|
| _ -> None)
|
||
|
prev
|
||
|
next
|
||
|
|
||
|
let pp fmt astate =
|
||
|
M.pp ~pp_value:ValueDomain.pp fmt astate
|
||
|
|
||
|
(* hide empty so we don't accidentally satisfy the WithBottom signature *)
|
||
|
let empty = `This_domain_is_not_pointed
|
||
|
end
|
||
|
|
||
8 years ago
|
module BooleanAnd = struct
|
||
|
type astate = bool
|
||
|
|
||
|
let (<=) ~lhs ~rhs = lhs || not rhs
|
||
|
|
||
|
let join = (&&)
|
||
|
|
||
|
let widen ~prev ~next ~num_iters:_ =
|
||
|
join prev next
|
||
|
|
||
|
let pp fmt astate =
|
||
|
F.fprintf fmt "%b" astate
|
||
|
end
|
||
8 years ago
|
|
||
|
module BooleanOr = struct
|
||
|
type astate = bool
|
||
|
|
||
|
let (<=) ~lhs ~rhs = not lhs || rhs
|
||
|
|
||
|
let join = (||)
|
||
|
|
||
|
let widen ~prev ~next ~num_iters:_ =
|
||
|
join prev next
|
||
|
|
||
|
let pp fmt astate =
|
||
|
F.fprintf fmt "%b" astate
|
||
|
end
|