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 =
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
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