From b521f5d723b6f46043b0ddbb95dbc36d0952ab70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr> Date: Thu, 20 Jan 2022 14:02:09 +0100 Subject: [PATCH] [kernel] Visitor: adds a function to visit all function definitions of a file. For visitors that only need function C bodies, replaces uses of [visitFramacFileSameGlobals], which visits all globals of a file, by [visitFramacFileFunctions], which visits only function definitions. Also optimizes these visitors by skipping the visit of some nodes, especially the visit of functions specifications and code annotations. --- src/kernel_internals/typing/allocates.ml | 10 +++++++--- src/kernel_internals/typing/asm_contracts.ml | 8 +++++++- src/kernel_internals/typing/unroll_loops.ml | 9 ++++++++- src/kernel_services/analysis/exn_flow.ml | 15 +++++++++++++-- src/kernel_services/ast_transformations/inline.ml | 7 ++++++- src/kernel_services/visitors/visitor.ml | 7 +++++++ src/kernel_services/visitors/visitor.mli | 7 +++++++ src/plugins/value/legacy/eval_annots.ml | 9 +++++++-- src/plugins/value/partitioning/split_return.ml | 6 +++++- 9 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/kernel_internals/typing/allocates.ml b/src/kernel_internals/typing/allocates.ml index dec3566fe21..92f755e9cbb 100644 --- a/src/kernel_internals/typing/allocates.ml +++ b/src/kernel_internals/typing/allocates.ml @@ -57,11 +57,15 @@ class vis_add_loop_allocates = ); Cil.DoChildren - method! vinst _ = Cil.SkipChildren - + method! vinst _ = SkipChildren + method! vexpr _ = SkipChildren + method! vlval _ = SkipChildren + method! vtype _ = SkipChildren + method! vspec _ = SkipChildren + method! vcode_annot _ = SkipChildren end let add_allocates_nothing () = Globals.Functions.iter add_allocates_nothing_funspec; let vis = new vis_add_loop_allocates in - Visitor.visitFramacFileSameGlobals vis (Ast.get ()) + Visitor.visitFramacFileFunctions vis (Ast.get ()) diff --git a/src/kernel_internals/typing/asm_contracts.ml b/src/kernel_internals/typing/asm_contracts.ml index 55c5b0fb1f4..c2c8e143093 100644 --- a/src/kernel_internals/typing/asm_contracts.ml +++ b/src/kernel_internals/typing/asm_contracts.ml @@ -221,11 +221,17 @@ class visit_assembly = ~dkey:Kernel.dkey_asm_contracts "Ignoring basic assembly instruction"; Cil.SkipChildren | _ -> Cil.SkipChildren + + method! vexpr _ = SkipChildren + method! vlval _ = SkipChildren + method! vtype _ = SkipChildren + method! vspec _ = SkipChildren + method! vcode_annot _ = SkipChildren end let transform file = if Kernel.AsmContractsGenerate.get() then - Visitor.visitFramacFileSameGlobals (new visit_assembly) file + Visitor.visitFramacFileFunctions (new visit_assembly) file let () = File.add_code_transformation_after_cleanup diff --git a/src/kernel_internals/typing/unroll_loops.ml b/src/kernel_internals/typing/unroll_loops.ml index 89c96fbb3a5..1242f533128 100644 --- a/src/kernel_internals/typing/unroll_loops.ml +++ b/src/kernel_internals/typing/unroll_loops.ml @@ -709,6 +709,13 @@ class do_it global_find_init ((force:bool),(times:int)) = object(self) ChangeDoChildrenPost (s, fgh) | _ -> DoChildren + + method! vinst _ = SkipChildren + method! vexpr _ = SkipChildren + method! vlval _ = SkipChildren + method! vtype _ = SkipChildren + method! vspec _ = SkipChildren + method! vcode_annot _ = SkipChildren end (* Performs unrolling transformation without using -ulevel option. @@ -723,7 +730,7 @@ let apply_transformation ?(force=true) nb file = in let visitor = new do_it global_find_init (force, nb) in Kernel.debug ~dkey "Using -ulevel %d option and UNROLL loop pragmas@." nb; - visitFramacFileSameGlobals (visitor:>Visitor.frama_c_visitor) file; + visitFramacFileFunctions (visitor:>Visitor.frama_c_visitor) file; if !ast_has_changed then Ast.mark_as_changed () else begin Kernel.debug ~dkey diff --git a/src/kernel_services/analysis/exn_flow.ml b/src/kernel_services/analysis/exn_flow.ml index f6dd804a26c..ad3a19d463a 100644 --- a/src/kernel_services/analysis/exn_flow.ml +++ b/src/kernel_services/analysis/exn_flow.ml @@ -65,11 +65,17 @@ class all_exn = all_exn <- Cil_datatype.Typ.Set.add (purify t) all_exn; SkipChildren | _ -> DoChildren + method! vinst _ = SkipChildren + method! vexpr _ = SkipChildren + method! vlval _ = SkipChildren + method! vtype _ = SkipChildren + method! vspec _ = SkipChildren + method! vcode_annot _ = SkipChildren end let compute_all_exn () = let vis = new all_exn in - Visitor.visitFramacFileSameGlobals (vis:>Visitor.frama_c_visitor) (Ast.get()); + Visitor.visitFramacFileFunctions (vis:>Visitor.frama_c_visitor) (Ast.get()); vis#get_exn let all_exn () = All_exn.memo compute_all_exn @@ -259,6 +265,11 @@ class exn_visit = in DoChildrenPost after_visit + method! vexpr _ = SkipChildren + method! vlval _ = SkipChildren + method! vtype _ = SkipChildren + method! vspec _ = SkipChildren + method! vcode_annot _ = SkipChildren end let compute_kf kf = @@ -857,7 +868,7 @@ let prepare_file f = let remove_exn f = if Kernel.RemoveExn.get() then begin - Visitor.visitFramacFileSameGlobals (new exn_visit) f; + Visitor.visitFramacFileFunctions (new exn_visit) f; let vis = new erase_exn in Visitor.visitFramacFile (vis :> Visitor.frama_c_visitor) f; let funs = vis#modified_funcs in diff --git a/src/kernel_services/ast_transformations/inline.ml b/src/kernel_services/ast_transformations/inline.ml index b8cddec6cc6..8e3d83b946f 100644 --- a/src/kernel_services/ast_transformations/inline.ml +++ b/src/kernel_services/ast_transformations/inline.ml @@ -342,6 +342,11 @@ let inliner functions_to_inline = object (self) let kf = Globals.Functions.get f.svar in already_visited <- Cil_datatype.Kf.Set.add kf functions_to_inline; f) + method! vexpr _ = SkipChildren + method! vlval _ = SkipChildren + method! vtype _ = SkipChildren + method! vspec _ = SkipChildren + method! vcode_annot _ = SkipChildren end let remove_local_statics = object @@ -379,7 +384,7 @@ end let inline_calls ast = if not (InlineCalls.is_empty ()) then begin let functions = InlineCalls.get() in - Visitor.visitFramacFileSameGlobals (inliner functions) ast; + Visitor.visitFramacFileFunctions (inliner functions) ast; Cil_datatype.Kf.Set.iter (fun kf -> ignore (Visitor.visitFramacKf remove_local_statics kf)) functions; diff --git a/src/kernel_services/visitors/visitor.ml b/src/kernel_services/visitors/visitor.ml index 1121a89660d..fdb824e963c 100644 --- a/src/kernel_services/visitors/visitor.ml +++ b/src/kernel_services/visitors/visitor.ml @@ -871,6 +871,13 @@ let visitFramacFunction vis f = Option.iter vis#set_current_kf old_current_kf; vis#fill_global_tables; f' +let visitFramacFileFunctions vis file = + let process_one_global = function + | GFun (fundec, _) -> ignore (visitFramacFunction vis fundec) + | _ -> () + in + Cil.iterGlobals file process_one_global + let visitFramacKf vis kf = let glob = Ast.def_or_last_decl (Kernel_function.get_vi kf) in ignore (visitFramacGlobal vis glob); diff --git a/src/kernel_services/visitors/visitor.mli b/src/kernel_services/visitors/visitor.mli index 8b0a5da0742..87ae254349d 100644 --- a/src/kernel_services/visitors/visitor.mli +++ b/src/kernel_services/visitors/visitor.mli @@ -115,6 +115,13 @@ val visitFramacFile: frama_c_visitor -> file -> unit @plugin development guide *) val visitFramacFileSameGlobals: frama_c_visitor -> file -> unit +(** Visit all function definitions of a file. Use this function instead of + {!Visitor.visitFramacFile} or {!Visitor.visitFramacFileSameGlobals} if your + visitor only needs function bodies to avoid visiting other globals, + including libc functions and their specifications. + @since Frama-c+dev *) +val visitFramacFileFunctions: frama_c_visitor -> file -> unit + (** Visit a global. {b Warning} Do not call this function during another visit using the diff --git a/src/plugins/value/legacy/eval_annots.ml b/src/plugins/value/legacy/eval_annots.ml index 910bb4dfce7..6f8a65f402a 100644 --- a/src/plugins/value/legacy/eval_annots.ml +++ b/src/plugins/value/legacy/eval_annots.ml @@ -96,11 +96,16 @@ let mark_unreachable () = end; Cil.DoChildren - method! vinst _ = Cil.SkipChildren + method! vinst _ = SkipChildren + method! vexpr _ = SkipChildren + method! vlval _ = SkipChildren + method! vtype _ = SkipChildren + method! vspec _ = SkipChildren + method! vcode_annot _ = SkipChildren end in Annotations.iter_all_code_annot do_code_annot; - Visitor.visitFramacFile unreach (Ast.get ()) + Visitor.visitFramacFileFunctions unreach (Ast.get ()) let c_labels kf cs = if !Db.Value.use_spec_instead_of_definition kf then diff --git a/src/plugins/value/partitioning/split_return.ml b/src/plugins/value/partitioning/split_return.ml index fe4ee995d77..0ecb7b4edfc 100644 --- a/src/plugins/value/partitioning/split_return.ml +++ b/src/plugins/value/partitioning/split_return.ml @@ -208,6 +208,10 @@ module ReturnUsage = struct method result () = summarize_by_lv usage + + method! vtype _ = SkipChildren + method! vspec _ = SkipChildren + method! vcode_annot _ = SkipChildren end (* For functions returning pointers, add a split on NULL/non-NULL *) @@ -223,7 +227,7 @@ module ReturnUsage = struct let compute file = let vis = new visitorVarUsage in - Visitor.visitFramacFileSameGlobals (vis:> Visitor.frama_c_visitor) file; + Visitor.visitFramacFileFunctions (vis:> Visitor.frama_c_visitor) file; let split_compared = vis#result () in let split_null_pointers = add_null_pointers_split split_compared in split_null_pointers -- GitLab