File: src/storelattice.ml (return to index)



Statistics:  
kind coverage
binding 51 / 52 (98%)
sequence 0 / 2 (0%)
for 0 / 0 (-%)
if/then 43 / 46 (93%)
try 5 / 6 (83%)
while 0 / 0 (-%)
match/function 55 / 58 (94%)
kind coverage
class expression 0 / 0 (-%)
class initializer 0 / 0 (-%)
class method 0 / 0 (-%)
class value 0 / 0 (-%)
toplevel expression 0 / 0 (-%)
lazy operator 34 / 34 (100%)



Source:

fold all unfold all
000001| (** Abstract store datatype and operations *)
000002|  
000003| module VL = Valuelattice
000004| module PL = Proplattice
000005| module StoreMap = Map.Make(struct type t = int
000006|                                   let compare i i' = (*[33450163]*)i - i' end)
000007| module Str = Stringlattice
000008|  
000009| type elem = Proplattice.elem StoreMap.t
000010|  
000011| (*  leq : elem -> elem -> bool  *) 
000012| let leq st0 st1 =
000013|   (*[1209488]*)StoreMap.fold (fun lab obj acc ->
000014|     (*[8470200]*)let obj' = try (*[8470200]*)StoreMap.find lab st1
000015|                with Not_found -> (*[7385632]*)PL.bot
000016|     in (*[8470200]*)acc && (*[2144626]*)PL.leq obj obj') st0 true
000017|  
000018| (*  eq : elem -> elem -> bool  *) 
000019| let eq = (*[1]*)StoreMap.equal Proplattice.eq
000020|  
000021| (*  join : elem -> elem -> elem  *) 
000022| let join st0 st1 = (*[498075]*)StoreMap.merge (fun lab obj0 obj1 -> match obj0,obj1 with
000023|   | None,_ -> (*[603274]*)obj1
000024|   | _,None -> (*[1344051]*)obj0
000025|   | Some obj0,Some obj1 -> (*[3200982]*)Some (PL.join obj0 obj1)) st0 st1
000026|  
000027| (*  meet : elem -> elem -> elem  *) 
000028| let meet st0 st1 = (*[80332]*)StoreMap.merge (fun lab obj0 obj1 -> match obj0,obj1 with
000029|   | None,_ -> (*[310131]*)None
000030|   | _,None -> (*[173270]*)None
000031|   | Some obj0, Some obj1 -> (*[322438]*)Some (PL.meet obj0 obj1)) st0 st1
000032|  
000033| (*  bot : elem  *)
000034| let bot = (*[1]*)StoreMap.empty
000035|  
000036|  
000037| (** {3 Lattice operations } *)
000038|  
000039| (*  is_bot : store -> bool  *)
000040| let is_bot st = (*[515955]*)leq st bot
000041|  
000042| (*  add_label : store -> label -> PL -> store *)
000043| let add_label st lab prop =
000044|   (*[510808]*)StoreMap.add lab prop st
000045|  
000046| (*  find_label_exn : store -> label -> PL *)
000047| let find_label_exn st lab =
000048|   (*[1388314]*)StoreMap.find lab st
000049|  
000050| (*  find_label : store -> label -> PL *)
000051| let find_label st lab =
000052|   (*[1154616]*)try (*[1154616]*)find_label_exn st lab
000053|   with Not_found -> (*[686962]*)PL.bot
000054|  
000055| (*  fold_labels_scopechain : (label list -> 'a -> 'a) -> store -> label -> 'a -> 'a *)
000056| let fold_labels_scopechain f st lab acc =
000057|   (*[0]*)if is_bot st
000058|   then (*[0]*)acc
000059|   else
000060|     (*[0]*)try
000061|       (*[0]*)let pl = find_label st lab in
000062|       (match pl with
000063|         | PL.Bot      -> (*[0]*)acc
000064|         | PL.Table pl -> (*[0]*)PL.ScopeChainSet.fold f pl.PL.scopechain acc)
000065|     with Not_found -> (*failwith ("No scope chain installed for label " ^ (string_of_int lab))*)
000066|       ((*[0]*)Printf.printf "No scope chain installed for label %i\n" lab;
000067|        (*[0]*)acc)
000068|  
000069| (*  lookup_str_prop : store -> VL -> str -> VL *)
000070| let lookup_str_prop st vlat prop =
000071|   (*[31111]*)if (*[31111]*)is_bot st || (*[29497]*)VL.is_bot vlat
000072|   then (*[2581]*)VL.bot
000073|   else
000074|     (*[28530]*)let tables = vlat.VL.tables in
000075|     (*[28530]*)VL.LabelSet.fold (fun lab acc -> 
000076|       (*[90600]*)let plat = find_label st lab in
000077|       (*[90600]*)VL.join acc (PL.find prop plat) ) tables VL.bot
000078|  
000079| (*  lookup_all_keys : store -> VL -> VL *)
000080| let lookup_all_keys st vlat =
000081|   (*[23510]*)let tables = vlat.VL.tables in
000082|   (*[23510]*)VL.LabelSet.fold (fun lab acc -> 
000083|     (*[63382]*)let plat = find_label st lab in
000084|     (*[63382]*)VL.join acc (PL.find_all_keys plat) ) tables VL.bot 
000085|  
000086| (*  lookup_all_str_props : store -> VL -> VL *)
000087| let lookup_all_str_props st vlat =
000088|   (*[31988]*)let tables = vlat.VL.tables in
000089|   (*[31988]*)VL.LabelSet.fold (fun lab acc -> 
000090|     (*[94383]*)let plat = find_label st lab in
000091|     (*[94383]*)VL.join acc (PL.find_all plat) ) tables VL.bot 
000092|  
000093| (*  lookup_all_nonstr_props : store -> VL -> VL *)
000094| let lookup_all_nonstr_props st vlat =
000095|   (*[28206]*)let tables = vlat.VL.tables in
000096|   (*[28206]*)VL.LabelSet.fold (fun lab acc -> 
000097|     (*[82412]*)let plat = find_label st lab in
000098|     (*[82412]*)VL.join acc (snd (PL.find_nonstr_defaults plat))) tables VL.bot 
000099|  
000100| (*  lookup_all_props : store -> VL -> VL *)
000101| let lookup_all_props st vlat =
000102|   (*[16729]*)VL.join (lookup_all_str_props st vlat) (lookup_all_nonstr_props st vlat)
000103|  
000104| (*  lookup_nonstr_default_prop : store -> VL -> VL -> VL *)
000105| let lookup_nonstr_default_prop st vlat vlat' =
000106|   (*[31720]*)if (*[31720]*)is_bot st (*|| VL.is_bot vlat*) || (*[29752]*)VL.is_bot vlat'
000107|   then (*[2932]*)VL.bot
000108|   else
000109|     (*[28788]*)let tables = vlat.VL.tables in
000110|     (*[28788]*)VL.LabelSet.fold (fun lab acc -> 
000111|       (*[84750]*)let plat        = find_label st lab in
000112|       (*[84750]*)let def_key,def = PL.find_nonstr_defaults plat in  (* Note: for non-str entries *)
000113|       (*[84750]*)let acc'        = VL.join VL.nil acc in
000114|       (*[84750]*)if VL.is_bot (VL.meet vlat' def_key)
000115|       then (*[71209]*)acc'
000116|       else (*[13541]*)VL.join acc' def) tables VL.bot 
000117|  
000118| (*  lookup_dyn_prop : store -> VL -> VL -> VL *)
000119| let lookup_dyn_prop st vlat vlat' = 
000120|   (*[72961]*)if (*[72961]*)is_bot st || (*[70592]*)VL.is_bot vlat  (* No indexed expr values *)
000121|                || (*[33427]*)VL.is_bot vlat' (* No indexing expr values *)
000122|   then (*[40521]*)VL.bot
000123|   else
000124|     (*[32440]*)let res = if VL.may_be_non_strings vlat'
000125|               then (*[16720]*)lookup_nonstr_default_prop st vlat vlat' (* all relevant default entries *)
000126|               else (*[15720]*)VL.bot in
000127|     (*[32440]*)let strres = match vlat'.VL.strings with
000128|                   | Str.Top     -> (*[5259]*)lookup_all_str_props st vlat
000129|                   | Str.Const s -> (*[21111]*)lookup_str_prop st vlat s
000130|                   | Str.Bot     -> (*[6070]*)VL.bot in
000131|     (*[32440]*)VL.join res strres
000132|  
000133| (*  raw_get : store -> VL -> VL -> VL *)
000134| let raw_get = (*[1]*)lookup_dyn_prop
000135|  
000136| (*  write_str_prop : store -> VL -> str -> VL -> store *)
000137| let write_str_prop st vlat prop vlat' =
000138|   (*[24582]*)if (*[24582]*)is_bot st || (*[22788]*)VL.is_bot vlat || (*[22764]*)VL.is_bot vlat' then (*[1835]*)bot else
000139|   (*[22747]*)let tables = vlat.VL.tables in
000140|   (*[22747]*)VL.LabelSet.fold
000141|     (fun lab stacc ->
000142|       (*[69723]*)try
000143|         (*[69723]*)let plat     = find_label_exn st lab in
000144|         (*[17687]*)let old_vlat = PL.find prop plat in (* can be improved if not (str <= def_key) *)
000145|         (*[17687]*)let new_plat = PL.add prop (VL.join vlat' (* join in default + weak update *)
000146|                                       (VL.exclude_nil old_vlat)) plat in
000147|                                       (* if prev. entry was nil (not present) filter it and add strongly *)
000148|         (*[17687]*)join (add_label st lab new_plat) stacc (* improvements: exclude nil from vlat', model removal *)
000149|       with Not_found -> ((*Printf.printf "Unknown allocation site label %i\n" lab;*)
000150|                           (*[52036]*)stacc)) tables bot
000151|  
000152| (*  write_all_str_props : store -> VL -> VL -> VL -> store *)
000153| let write_all_str_props st vlat0 (*vlat1*) vlat =
000154|   (*[23901]*)if (*[23901]*)is_bot st || (*[22926]*)VL.is_bot vlat0 || (*VL.is_bot vlat1 ||*) (*[21958]*)VL.is_bot vlat
000155|   then (*[1967]*)bot
000156|   else
000157|     (*[21934]*)let tables = vlat0.VL.tables in
000158|     (*[21934]*)VL.LabelSet.fold (fun lab stacc -> 
000159|       (*[68234]*)try
000160|         (*[68234]*)let plat     = find_label_exn st lab in
000161|         (*[17351]*)let new_plat = PL.add_all_str vlat plat in  (* weak updates all str entries -- incl.default_str *)
000162|         (*[17351]*)add_label stacc lab new_plat
000163|       with Not_found -> ((*Printf.printf "Unknown allocation site label %i\n" lab;*)
000164|                          (*[50883]*)stacc)) tables st
000165|  
000166| (*  write_default_nonstr_prop : store -> VL -> VL -> VL -> store *)
000167| let write_default_nonstr_prop st vlat0 vlat1 vlat =
000168|   (*[50545]*)if (*[50545]*)is_bot st || (*[49456]*)VL.is_bot vlat0 || (*[49431]*)VL.is_bot vlat1 || (*[49415]*)VL.is_bot vlat
000169|   then (*[1148]*)bot
000170|   else
000171|     (*[49397]*)let tables = vlat0.VL.tables in
000172|     (*[49397]*)VL.LabelSet.fold (fun lab stacc -> 
000173|       (*[146366]*)let plat = find_label st lab in
000174|       (*[146366]*)let old_def_key, old_def = PL.find_nonstr_defaults plat in
000175|       (*[146366]*)let new_plat = PL.add_nonstr_default (VL.join vlat1 old_def_key) (VL.join vlat old_def) plat in (* weak update in default *)
000176|       (*[146366]*)add_label stacc lab new_plat) tables st
000177|  
000178| (*  write_dyn_prop : store -> VL -> VL -> VL -> store *)
000179| let write_dyn_prop st vlat0 vlat1 vlat =
000180|   (*[37327]*)if (*[37327]*)is_bot st || (*[34734]*)VL.is_bot vlat0  (* No indexed expr values *)
000181|                || (*[34689]*)VL.is_bot vlat1  (* No indexing expr values *)
000182|                || (*[34644]*)VL.is_bot vlat   (* No value to write *)
000183|   then (*[2743]*)bot
000184|   else
000185|     (*[34584]*)let res = if VL.may_be_non_strings vlat1
000186|               then (*[34545]*)write_default_nonstr_prop st vlat0 (VL.exclude_strings vlat1) vlat (* write to all relevant default entries *)
000187|               else (*[39]*)bot in                                 (* don't *)
000188|     (*[34584]*)let strres = match vlat1.VL.strings with
000189|                   | Str.Top     -> (*[10901]*)write_all_str_props st vlat0 vlat
000190|                   | Str.Const s -> (*[11582]*)write_str_prop st vlat0 s vlat
000191|                   | Str.Bot     -> (*[12101]*)bot in
000192|     (*[34584]*)if is_bot res
000193|     then (*[39]*)strres
000194|     else (*[34545]*)join res strres
000195|  
000196| (*  raw_set : store -> VL -> VL -> VL -> store *)
000197| let raw_set = (*[1]*)write_dyn_prop
000198|  
000199| (*  get_metatable : store -> VL -> VL *)
000200| let get_metatable st vlat =   (* fixme: strings have a metatable with a __index metamethod? *)
000201|   (*[16993]*)if (*[16993]*)is_bot st || (*[14847]*)VL.is_bot vlat
000202|   then (*[3128]*)VL.bot
000203|   else        (* semantics: http://www.lua.org/manual/5.1/manual.html#pdf-getmetatable  *)
000204|     (*[13865]*)let tables = vlat.VL.tables in
000205|     (*[13865]*)VL.LabelSet.fold (fun lab acc -> 
000206|       (*[41718]*)let plat         = find_label st lab in      (* for each table:  *)
000207|       (*[41718]*)let metatabs     = PL.get_metatable plat in  (*    lookup metatable *)
000208|       (*[41718]*)let metametatabs = 
000209|         VL.LabelSet.fold (fun metalab acc ->
000210|           (*[11729]*)let metatab     = find_label st metalab in         (*    and __metatable in metatable *)
000211|           (*[11729]*)let metametatab = PL.find "__metatable" metatab in
000212|           (*[11729]*)if VL.may_be_nil metametatab (* second lookup may fail: include metatab *)
000213|           then (*[3629]*)VL.join (VL.table metalab) (VL.join (VL.exclude_nil metametatab) acc)
000214|           else (*[8100]*)VL.join (VL.exclude_nil metametatab) acc) metatabs.VL.tables VL.bot in
000215|       (*[41718]*)VL.join acc
000216|         (VL.join (VL.exclude_tables metatabs) metametatabs)) tables VL.bot
000217|  
000218| (*  set_metatable : store -> VL -> VL -> store *)
000219| let set_metatable st vlat metavlat =
000220|   (*[19018]*)if is_bot st
000221|   then (*[2221]*)bot
000222|   else (* semantics: http://www.lua.org/manual/5.1/manual.html#pdf-setmetatable  *)
000223|   (*[16797]*)let tables = vlat.VL.tables in
000224|   (*[16797]*)VL.LabelSet.fold (fun lab stacc ->
000225|     (*[49277]*)try
000226|       (*[49277]*)let plat         = find_label_exn st lab in
000227|       (*[12390]*)let old_metavlat = PL.get_metatable plat in
000228|       (*[12390]*)join stacc
000229|        (join
000230|          (* no metatable present -> set it *)
000231|          (if VL.may_be_nil old_metavlat
000232|           then (* normal operation *)
000233|              (*[8316]*)let plat' = PL.set_metatable (VL.exclude_nil metavlat) plat in
000234|              (*[8316]*)add_label st lab plat'
000235|           else (*[4074]*)bot)
000236|  
000237|          (* metatable labels present, potentially with __metatable fields *)
000238|          (VL.LabelSet.fold (fun metalab acc ->
000239|            (*[13815]*)let metatab     = find_label st metalab in
000240|            (*[13815]*)let metametatab = PL.find "__metatable" metatab in
000241|            (*[13815]*)if VL.may_be_nil metametatab
000242|            then (* may fail to have __metatable field, i.e., may succeed -> update *)
000243|              (*[4178]*)if (*[4178]*)VL.may_be_nil metavlat && (*[1903]*)VL.is_nil metavlat (* "rhs" definitely nil *)
000244|              then
000245|                (*[0]*)let plat' = PL.set_metatable_absent plat in (* weak update: delete+keep = maybe absent *)
000246|                (*[0]*)join acc (add_label st lab plat')
000247|              else (* weak update *)
000248|                (*[4178]*)if VL.may_be_nil metavlat (* maybe delete, maybe write = maybe absent *)
000249|                then
000250|                  (*[1903]*)let plat' = PL.set_metatable (VL.join old_metavlat (VL.exclude_nil metavlat)) plat in
000251|                  (*[1903]*)let plat' = PL.set_metatable_absent plat' in
000252|                  (*[1903]*)join acc (add_label st lab plat')
000253|                else (* just write *)
000254|                  (*[2275]*)let plat' = PL.set_metatable (VL.join old_metavlat (VL.exclude_nil metavlat)) plat in
000255|                  (*[2275]*)join acc (add_label st lab plat')
000256|            else
000257|              (*[9637]*)acc (* error, so return bot, i.e., no effect on acc *) ) old_metavlat.VL.tables bot))
000258|     with Not_found -> ((*Printf.printf "Unknown allocation site label %i\n" lab;*)
000259|                        (*[36887]*)stacc)) tables bot
000260|  
000261| (* The following function helps to implement the metatable(obj)[event] notation *)
000262| (*  modelling an internal metatable lookup *)
000263| (* This operation differs from the semantics of the API getmetatable (it is unprotected)  *)
000264| (*  despite the explanation in http://www.lua.org/manual/5.1/manual.html#2.8 *)
000265| (*  myget_metatable : store -> VL -> VL *)
000266| let myget_metatable st vlat =   (* fixme: strings have a metatable with a __index metamethod? *)
000267|   (*[61893]*)if (*[61893]*)is_bot st || (*[60236]*)VL.is_bot vlat
000268|   then (*[2629]*)VL.bot
000269|   else
000270|     (*[59264]*)let tables = vlat.VL.tables in
000271|     (*[59264]*)VL.LabelSet.fold (fun lab acc -> 
000272|       (*[198598]*)let plat     = find_label st lab in       (* for each table:  *)
000273|       (*[198598]*)let metatabs = PL.get_metatable plat in   (*    lookup metatable *)
000274|       (*[198598]*)VL.join acc metatabs) tables VL.bot
000275|  
000276| (*  lookup_event : ST -> VL -> string -> VL *)
000277| let lookup_event st vlat strevent =   (* corresponds to metatable(obj)[event] notation in manual *)
000278|   (*[54518]*)if (*[54518]*)is_bot st || (*[52850]*)VL.is_bot vlat
000279|   then (*[2625]*)VL.bot
000280|   else
000281|     (*[51893]*)let base = myget_metatable st vlat in  (* http://www.lua.org/manual/5.1/manual.html#2.8 *)
000282|     (*[51893]*)let res  = raw_get st (VL.exclude_nil base) (VL.string strevent) in
000283|     (*[51893]*)if VL.may_be_nil base
000284|     then (*[19946]*)VL.join VL.nil res
000285|     else (*[31947]*)res
000286|  
000287| (*  getbinhandler : ST -> VL -> VL -> string -> VL *)
000288| let getbinhandler st vlat0 vlat1 strevent =
000289|   (*[30000]*)if (*[30000]*)is_bot st || (*[26109]*)VL.is_bot vlat0 || (*[24183]*)VL.is_bot vlat1 (* FIXED *)
000290|   then (*[7741]*)VL.bot
000291|   else (*[22259]*)VL.or_join (lookup_event st vlat0 strevent)
000292|                   (lookup_event st vlat1 strevent)
000293|  
000294|  
000295| (** {3 Pretty printing} *)
000296|  
000297| (*  pprint : store -> unit  *)
000298| let pprint st =
000299|   begin
000300|     Format.printf "{ @[<v 0>";
000301|     ignore (StoreMap.fold (fun lab plat first -> 
000302|       if first
000303|       then (Format.printf "%-8i -> " lab; PL.pprint plat; false)
000304|       else
000305|         begin
000306|           Format.print_space ();
000307|           Format.printf "%-8i -> " lab;
000308|           PL.pprint plat;
000309|           false
000310|         end) st true);
000311|     Format.printf "@]}";
000312|   end
000313|  
000314| (*  to_string : elem -> string  *)
000315| let to_string st =
000316|   let buf = Buffer.create 128 in
000317|   let out,flush = Format.get_formatter_output_functions () in (* save previous outputters *)
000318|   begin
000319|     Format.set_formatter_output_functions (Buffer.add_substring buf) (fun () -> ());
000320|     pprint st;
000321|     Format.print_flush ();
000322|     Format.set_formatter_output_functions out flush;          (* restore previous outputters *)
000323|     Buffer.contents buf
000324|   end

Legend:
   some code - line containing no point
   some code - line containing only visited points
   some code - line containing only unvisited points
   some code - line containing both visited and unvisited points