Skip to content

Commit 4031cb2

Browse files
authored
Merge pull request #1690 from arkocal/hashcachedcontextlifter
HashCachedContextLifter: Introduce the lifter and the option
2 parents a935456 + 6671ad9 commit 4031cb2

File tree

4 files changed

+104
-13
lines changed

4 files changed

+104
-13
lines changed

src/common/domains/printable.ml

+14-13
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ sig
2626
(* For hashconsing together with incremental we need to re-hashcons old values.
2727
* For HashconsLifter.D this is done on any lattice operation, so we can replace x with `join bot x` to hashcons it again and get a new tag for it.
2828
* For HashconsLifter.C we call hashcons only in `context` which is in Analyses.Spec but not in Analyses.GlobConstrSys, i.e. not visible to the solver. *)
29-
(* The default for this should be identity, except for HConsed below where we want to have the side-effect and return a value with the updated tag. *)
29+
(* The default for functors should pass the call to their argument modules, except for HConsed below where we want to have the side-effect and return a value with the updated tag. *)
3030
val relift: t -> t
3131
end
3232

@@ -162,39 +162,40 @@ struct
162162
let arbitrary () = QCheck.map ~rev:unlift lift (Base.arbitrary ())
163163
end
164164

165-
module HashCached (M: S) =
165+
module HashCached (Base: S) =
166166
struct
167-
module LazyHash = LazyEval.Make (struct type t = M.t type result = int let eval = M.hash end)
167+
module LazyHash = LazyEval.Make (struct type t = Base.t type result = int let eval = Base.hash end)
168168

169-
let name () = "HashCached " ^ M.name ()
169+
let name () = "HashCached " ^ Base.name ()
170170

171171
type t =
172172
{
173-
m: M.t;
173+
m: Base.t;
174174
lazy_hash: LazyHash.t;
175175
}
176176

177177
let lift m = {m; lazy_hash = LazyHash.make m}
178178
let unlift {m; _} = m
179+
let relift x = lift @@ Base.relift x.m
179180

180181
let lift_f f x = f (unlift x)
181182
let lift_f' f x = lift @@ lift_f f x
182183
let lift_f2 f x y = f (unlift x) (unlift y)
183184
let lift_f2' f x y = lift @@ lift_f2 f x y
184185

185-
let equal = lift_f2 M.equal
186-
let compare = lift_f2 M.compare
186+
let equal = lift_f2 Base.equal
187+
let compare = lift_f2 Base.compare
187188
let hash x = LazyHash.force x.lazy_hash
188-
let show = lift_f M.show
189+
let show = lift_f Base.show
189190

190-
let pretty () = lift_f (M.pretty ())
191+
let pretty () = lift_f (Base.pretty ())
191192

192-
let printXml f = lift_f (M.printXml f)
193-
let to_yojson = lift_f (M.to_yojson)
193+
let printXml f = lift_f (Base.printXml f)
194+
let to_yojson = lift_f (Base.to_yojson)
194195

195-
let arbitrary () = QCheck.map ~rev:unlift lift (M.arbitrary ())
196+
let arbitrary () = QCheck.map ~rev:unlift lift (Base.arbitrary ())
196197

197-
let tag = lift_f M.tag
198+
let tag = lift_f Base.tag
198199
end
199200

200201

src/config/options.schema.json

+7
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,13 @@
513513
"type": "boolean",
514514
"default": true
515515
},
516+
"hashcached": {
517+
"title": "ana.opt.hashcached",
518+
"description":
519+
"Should we try to save memory and speed up equality by caching hashes of contexts? This is useful when hashconsing is off",
520+
"type": "boolean",
521+
"default": false
522+
},
516523
"equal": {
517524
"title": "ana.opt.equal",
518525
"description":

src/framework/control.ml

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ let spec_module: (module Spec) Lazy.t = lazy (
2828
|> lift true (module WidenContextLifterSide) (* option checked in functor *)
2929
(* hashcons before witness to reduce duplicates, because witness re-uses contexts in domain and requires tag for PathSensitive3 *)
3030
|> lift (get_bool "ana.opt.hashcons" || arg_enabled) (module HashconsContextLifter)
31+
|> lift (get_bool "ana.opt.hashcached") (module HashCachedContextLifter)
3132
|> lift arg_enabled (module HashconsLifter)
3233
|> lift arg_enabled (module WitnessConstraints.PathSensitive3)
3334
|> lift (not arg_enabled) (module PathSensitive2)

src/lifters/specLifters.ml

+82
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,88 @@ struct
180180
let event man e oman = S.event (conv man) e (conv oman)
181181
end
182182

183+
(** Lifts a [Spec] so that the context is [HashCached]. *)
184+
module HashCachedContextLifter (S:Spec)
185+
: Spec with module D = S.D
186+
and module G = S.G
187+
and module C = Printable.HashCached (S.C)
188+
=
189+
struct
190+
module D = S.D
191+
module G = S.G
192+
module C = Printable.HashCached (S.C)
193+
module V = S.V
194+
module P = S.P
195+
196+
let name () = S.name () ^" context hashcached"
197+
198+
type marshal = S.marshal
199+
let init = S.init
200+
let finalize = S.finalize
201+
202+
let startstate = S.startstate
203+
let exitstate = S.exitstate
204+
let morphstate = S.morphstate
205+
206+
let conv man =
207+
{ man with context = (fun () -> C.unlift (man.context ())) }
208+
209+
let context man fd = C.lift % S.context (conv man) fd
210+
let startcontext () = C.lift @@ S.startcontext ()
211+
212+
let sync man reason =
213+
S.sync (conv man) reason
214+
215+
let query man (type a) (q: a Queries.t): a Queries.result =
216+
match q with
217+
| Queries.IterPrevVars f ->
218+
let g i (n, c, j) e = f i (n, Obj.repr (C.lift (Obj.obj c)), j) e in
219+
S.query (conv man) (Queries.IterPrevVars g)
220+
| _ -> S.query (conv man) q
221+
222+
let assign man lv e =
223+
S.assign (conv man) lv e
224+
225+
let vdecl man v =
226+
S.vdecl (conv man) v
227+
228+
let branch man e tv =
229+
S.branch (conv man) e tv
230+
231+
let body man f =
232+
S.body (conv man) f
233+
234+
let return man r f =
235+
S.return (conv man) r f
236+
237+
let asm man =
238+
S.asm (conv man)
239+
240+
let skip man =
241+
S.skip (conv man)
242+
243+
let enter man r f args =
244+
S.enter (conv man) r f args
245+
246+
let special man r f args =
247+
S.special (conv man) r f args
248+
249+
let combine_env man r fe f args fc es f_ask =
250+
S.combine_env (conv man) r fe f args (Option.map C.unlift fc) es f_ask
251+
252+
let combine_assign man r fe f args fc es f_ask =
253+
S.combine_assign (conv man) r fe f args (Option.map C.unlift fc) es f_ask
254+
255+
let threadenter man ~multiple lval f args =
256+
S.threadenter (conv man) ~multiple lval f args
257+
258+
let threadspawn man ~multiple lval f args fman =
259+
S.threadspawn (conv man) ~multiple lval f args (conv fman)
260+
261+
let paths_as_set man = S.paths_as_set (conv man)
262+
let event man e oman = S.event (conv man) e (conv oman)
263+
end
264+
183265
(* see option ana.opt.equal *)
184266
module OptEqual (S: Spec) = struct
185267
module D = struct include S.D let equal x y = x == y || equal x y end

0 commit comments

Comments
 (0)