[pulse] Avoid partitioning abstract values

Summary:
`partition` always constructs two new maps, which is expensive when
there are a lot of entries.  Let's avoid it if possible.

Reviewed By: jvillard

Differential Revision: D21684298

fbshipit-source-id: a8674d358
master
Sungkeun Cho 5 years ago committed by Facebook GitHub Bot
parent fd28651563
commit 719b72cb4f

@ -26,13 +26,10 @@ module type BaseDomainSig = sig
val update : ?stack:BaseStack.t -> ?heap:BaseMemory.t -> ?attrs:BaseAddressAttributes.t -> t -> t val update : ?stack:BaseStack.t -> ?heap:BaseMemory.t -> ?attrs:BaseAddressAttributes.t -> t -> t
val filter_addr : f:(AbstractValue.t -> bool) -> t -> t val filter_addr : f:(AbstractValue.t -> bool) -> t -> t
(**filter both heap and attrs *) (** filter both heap and attrs *)
val partition_addr : val filter_addr_with_discarded_attrs : f:(AbstractValue.t -> bool) -> t -> t * Attributes.t list
f:(AbstractValue.t -> bool) (** filter both heap and attrs with returning discarded attrs together *)
-> t
-> (BaseMemory.t * BaseAddressAttributes.t) * (BaseMemory.t * BaseAddressAttributes.t)
(**partition both heap and attrs *)
val pp : F.formatter -> t -> unit val pp : F.formatter -> t -> unit
end end
@ -63,12 +60,12 @@ module BaseDomainCommon = struct
update ~heap:heap' ~attrs:attrs' foot update ~heap:heap' ~attrs:attrs' foot
let partition_addr ~f foot = let filter_addr_with_discarded_attrs ~f foot =
let heap_yes, heap_no = BaseMemory.partition (fun address _ -> f address) foot.heap in let heap' = BaseMemory.filter (fun address _ -> f address) foot.heap in
let attrs_yes, attrs_no = let attrs', discarded_attributes =
BaseAddressAttributes.partition (fun address _ -> f address) foot.attrs BaseAddressAttributes.filter_with_discarded_attrs (fun address _ -> f address) foot.attrs
in in
((heap_yes, attrs_yes), (heap_no, attrs_no)) (update ~heap:heap' ~attrs:attrs' foot, discarded_attributes)
end end
(** represents the post abstract state at each program point *) (** represents the post abstract state at each program point *)
@ -339,10 +336,11 @@ let discard_unreachable ({pre; post} as astate) =
in in
let post_addresses = BaseDomain.reachable_addresses (post :> BaseDomain.t) in let post_addresses = BaseDomain.reachable_addresses (post :> BaseDomain.t) in
let live_addresses = AbstractValue.Set.union pre_addresses post_addresses in let live_addresses = AbstractValue.Set.union pre_addresses post_addresses in
let (heap_new, attrs_new), (_, attrs_unreachable) = let post_new, attrs_unreachable =
PostDomain.partition_addr ~f:(fun address -> AbstractValue.Set.mem address live_addresses) post PostDomain.filter_addr_with_discarded_attrs
~f:(fun address -> AbstractValue.Set.mem address live_addresses)
post
in in
let post_new = PostDomain.update ~heap:heap_new ~attrs:attrs_new post in
(* note: we don't call {!PulsePathCondition.simplify} *) (* note: we don't call {!PulsePathCondition.simplify} *)
let astate = let astate =
if phys_equal pre_new pre && phys_equal post_new post then astate if phys_equal pre_new pre && phys_equal post_new post then astate

@ -30,13 +30,10 @@ module type BaseDomainSig = sig
val update : ?stack:BaseStack.t -> ?heap:BaseMemory.t -> ?attrs:BaseAddressAttributes.t -> t -> t val update : ?stack:BaseStack.t -> ?heap:BaseMemory.t -> ?attrs:BaseAddressAttributes.t -> t -> t
val filter_addr : f:(AbstractValue.t -> bool) -> t -> t val filter_addr : f:(AbstractValue.t -> bool) -> t -> t
(**filter both heap and attrs *) (** filter both heap and attrs *)
val partition_addr : val filter_addr_with_discarded_attrs : f:(AbstractValue.t -> bool) -> t -> t * Attributes.t list
f:(AbstractValue.t -> bool) (** filter both heap and attrs with returning discarded attrs together *)
-> t
-> (BaseMemory.t * BaseAddressAttributes.t) * (BaseMemory.t * BaseAddressAttributes.t)
(**partition both heap and attrs *)
val pp : F.formatter -> t -> unit val pp : F.formatter -> t -> unit
end end
@ -143,7 +140,7 @@ val is_local : Var.t -> t -> bool
val find_post_cell_opt : AbstractValue.t -> t -> BaseDomain.cell option val find_post_cell_opt : AbstractValue.t -> t -> BaseDomain.cell option
val discard_unreachable : t -> t * AbstractValue.Set.t * BaseAddressAttributes.t val discard_unreachable : t -> t * AbstractValue.Set.t * Attributes.t list
(** [discard_unreachable astate] garbage collects unreachable addresses in the state to make it (** [discard_unreachable astate] garbage collects unreachable addresses in the state to make it
smaller, and retuns the new state, the live addresses, and the attributes of discarded addresses *) smaller, and retuns the new state, the live addresses, and the attributes of discarded addresses *)

@ -54,7 +54,11 @@ let empty = Graph.empty
let filter = Graph.filter let filter = Graph.filter
let partition = Graph.partition let filter_with_discarded_attrs f x =
fold
(fun k v ((x, discarded) as acc) -> if f k v then acc else (Graph.remove k x, v :: discarded))
x (x, [])
let pp = Graph.pp let pp = Graph.pp

@ -14,7 +14,8 @@ val empty : t
val filter : (AbstractValue.t -> Attributes.t -> bool) -> t -> t val filter : (AbstractValue.t -> Attributes.t -> bool) -> t -> t
val partition : (AbstractValue.t -> Attributes.t -> bool) -> t -> t * t val filter_with_discarded_attrs :
(AbstractValue.t -> Attributes.t -> bool) -> t -> t * Attributes.t list
val find_opt : AbstractValue.t -> t -> Attributes.t option val find_opt : AbstractValue.t -> t -> Attributes.t option

@ -316,7 +316,7 @@ let mark_address_of_stack_variable history variable location address astate =
let check_memory_leak_unreachable unreachable_attrs location astate = let check_memory_leak_unreachable unreachable_attrs location astate =
let check_memory_leak _ attributes result = let check_memory_leak result attributes =
let allocated_not_freed_opt = let allocated_not_freed_opt =
Attributes.fold attributes ~init:(None (* allocation trace *), false (* freed *)) Attributes.fold attributes ~init:(None (* allocation trace *), false (* freed *))
~f:(fun acc attr -> ~f:(fun acc attr ->
@ -335,7 +335,7 @@ let check_memory_leak_unreachable unreachable_attrs location astate =
| _ -> | _ ->
result result
in in
BaseAddressAttributes.fold check_memory_leak unreachable_attrs (Ok ()) List.fold unreachable_attrs ~init:(Ok ()) ~f:check_memory_leak
let remove_vars vars location astate = let remove_vars vars location astate =

Loading…
Cancel
Save