From 3b997e4882d1ec732eb30f8cfb514b6aca9397ab Mon Sep 17 00:00:00 2001 From: Jeremy Dubreil Date: Mon, 7 Nov 2016 11:35:34 -0800 Subject: [PATCH] [infer][java] Isolate the call to the JBir transformation to a single place Summary: Having only place where the code runs the transformation of the Java bytecode into the JBir reporesentation allows to more easily start manipulating the JBir representation and the bytecode together and progressively move the translation based on bytecode instead of JBir. Reviewed By: sblackshear Differential Revision: D4137576 fbshipit-source-id: c483528 --- infer/src/java/jFrontend.ml | 31 +++--- infer/src/java/jTrans.ml | 195 +++++++++++++++++++----------------- infer/src/java/jTrans.mli | 26 +++-- 3 files changed, 133 insertions(+), 119 deletions(-) diff --git a/infer/src/java/jFrontend.ml b/infer/src/java/jFrontend.ml index feb9e2caf..c58647576 100644 --- a/infer/src/java/jFrontend.ml +++ b/infer/src/java/jFrontend.ml @@ -77,11 +77,9 @@ let add_edges (** Add a concrete method. *) let add_cmethod source_file program linereader icfg cm proc_name = let cn, _ = JBasics.cms_split cm.Javalib.cm_class_method_signature in - let jmethod = (Javalib.ConcreteMethod cm) in - match JTrans.create_procdesc source_file program linereader icfg jmethod with + match JTrans.create_cm_procdesc source_file program linereader icfg cm proc_name with | None -> () - | Some _ when JTrans.is_java_native cm -> () - | Some procdesc -> + | Some (procdesc, impl) -> let start_node = Cfg.Procdesc.get_start_node procdesc in let exit_node = Cfg.Procdesc.get_exit_node procdesc in let exn_node = @@ -89,7 +87,6 @@ let add_cmethod source_file program linereader icfg cm proc_name = | Some node -> node | None -> failwithf "No exn node found for %s" (Procname.to_string proc_name) in - let impl = JTrans.get_implementation cm in let instrs = JBir.code impl in let context = JContext.create_context icfg procdesc impl cn source_file program in @@ -98,15 +95,6 @@ let add_cmethod source_file program linereader icfg cm proc_name = Cg.add_defined_node icfg.JContext.cg proc_name -(** Add an abstract method. *) -let add_amethod source_file program linereader icfg am proc_name = - let jmethod = (Javalib.AbstractMethod am) in - match JTrans.create_procdesc source_file program linereader icfg jmethod with - | None -> () - | Some _ -> - Cg.add_defined_node icfg.JContext.cg proc_name - - let path_of_cached_classname cn = let root_path = Filename.concat Config.results_dir "classnames" in let package_path = IList.fold_left Filename.concat root_path (JBasics.cn_package cn) in @@ -151,15 +139,22 @@ let create_icfg source_file linereader program icfg cn node = (* do not translate the method if there is a model for it *) L.out_debug "Skipping method with a model: %s@." (Procname.to_string proc_name) else - begin + try (* each procedure has different scope: start names from id 0 *) Ident.NameGenerator.reset (); match m with + | Javalib.AbstractMethod am -> + ignore (JTrans.create_am_procdesc program icfg am proc_name); + (* TODO #4040807: investigate why we need to mark asbtract methods as defined *) + Cg.add_defined_node icfg.JContext.cg proc_name + | Javalib.ConcreteMethod cm when JTrans.is_java_native cm -> + ignore (JTrans.create_native_procdesc program icfg cm proc_name) | Javalib.ConcreteMethod cm -> add_cmethod source_file program linereader icfg cm proc_name - | Javalib.AbstractMethod am -> - add_amethod source_file program linereader icfg am proc_name - end in + with JBasics.Class_structure_error _ -> + L.do_err + "create_icfg raised JBasics.Class_structure_error on %a@." + Procname.pp proc_name in Javalib.m_iter translate node diff --git a/infer/src/java/jTrans.ml b/infer/src/java/jTrans.ml index 441984cb2..4f46fb58e 100644 --- a/infer/src/java/jTrans.ml +++ b/infer/src/java/jTrans.ml @@ -230,106 +230,115 @@ let update_init_loc cn ms loc_start = try ignore(JBasics.ClassMap.find cn !init_loc_map) with Not_found -> init_loc_map := (JBasics.ClassMap.add cn loc_start !init_loc_map) +let trans_access = function + | `Default -> PredSymb.Default + | `Public -> PredSymb.Public + | `Private -> PredSymb.Private + | `Protected -> PredSymb.Protected + +let create_am_procdesc program icfg am proc_name : Cfg.Procdesc.t = + let cfg = icfg.JContext.cfg in + let tenv = icfg.JContext.tenv in + let m = Javalib.AbstractMethod am in + let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in + let formals = + formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in + let method_annotation = + JAnnotation.translate_method proc_name am.Javalib.am_annotations in + let procdesc = + let proc_attributes = + { (ProcAttributes.default proc_name Config.Java) with + ProcAttributes.access = trans_access am.Javalib.am_access; + exceptions = IList.map JBasics.cn_name am.Javalib.am_exceptions; + formals; + is_abstract = true; + is_bridge_method = am.Javalib.am_bridge; + is_defined = true; + is_synthetic_method = am.Javalib.am_synthetic; + method_annotation; + ret_type = JTransType.return_type program tenv ms; + } in + Cfg.create_proc_desc cfg proc_attributes in + let start_kind = Cfg.Node.Start_node proc_name in + let start_node = Cfg.Procdesc.create_node procdesc Location.dummy start_kind [] in + let exit_kind = (Cfg.Node.Exit_node proc_name) in + let exit_node = Cfg.Procdesc.create_node procdesc Location.dummy exit_kind [] in + Cfg.Procdesc.node_set_succs_exn procdesc start_node [exit_node] [exit_node]; + Cfg.Procdesc.set_start_node procdesc start_node; + Cfg.Procdesc.set_exit_node procdesc exit_node; + procdesc + +let create_native_procdesc program icfg cm proc_name = + let cfg = icfg.JContext.cfg in + let tenv = icfg.JContext.tenv in + let m = Javalib.ConcreteMethod cm in + let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in + let formals = + formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in + let method_annotation = + JAnnotation.translate_method proc_name cm.Javalib.cm_annotations in + let proc_attributes = + { (ProcAttributes.default proc_name Config.Java) with + ProcAttributes.access = trans_access cm.Javalib.cm_access; + exceptions = IList.map JBasics.cn_name cm.Javalib.cm_exceptions; + formals; + is_bridge_method = cm.Javalib.cm_bridge; + is_synthetic_method = cm.Javalib.cm_synthetic; + method_annotation; + ret_type = JTransType.return_type program tenv ms; + } in + Cfg.create_proc_desc cfg proc_attributes + (** Creates a procedure description. *) -let create_procdesc source_file program linereader icfg m : Cfg.Procdesc.t option = +let create_cm_procdesc source_file program linereader icfg cm proc_name = let cfg = icfg.JContext.cfg in let tenv = icfg.JContext.tenv in + let m = Javalib.ConcreteMethod cm in let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in - let proc_name = JTransType.translate_method_name m in - let trans_access = function - | `Default -> PredSymb.Default - | `Public -> PredSymb.Public - | `Private -> PredSymb.Private - | `Protected -> PredSymb.Protected in try + let impl = get_implementation cm in let procdesc = - match m with - | Javalib.AbstractMethod am -> (* create a procdesc with empty body *) - let formals = - formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in - let method_annotation = - JAnnotation.translate_method proc_name am.Javalib.am_annotations in - let procdesc = - let proc_attributes = - { (ProcAttributes.default proc_name Config.Java) with - ProcAttributes.access = trans_access am.Javalib.am_access; - exceptions = IList.map JBasics.cn_name am.Javalib.am_exceptions; - formals; - is_abstract = true; - is_bridge_method = am.Javalib.am_bridge; - is_defined = true; - is_synthetic_method = am.Javalib.am_synthetic; - method_annotation; - ret_type = JTransType.return_type program tenv ms; - } in - Cfg.create_proc_desc cfg proc_attributes in - let start_kind = Cfg.Node.Start_node proc_name in - let start_node = Cfg.Procdesc.create_node procdesc Location.dummy start_kind [] in - let exit_kind = (Cfg.Node.Exit_node proc_name) in - let exit_node = Cfg.Procdesc.create_node procdesc Location.dummy exit_kind [] in - Cfg.Procdesc.node_set_succs_exn procdesc start_node [exit_node] [exit_node]; - Cfg.Procdesc.set_start_node procdesc start_node; - Cfg.Procdesc.set_exit_node procdesc exit_node; - procdesc - | Javalib.ConcreteMethod cm when is_java_native cm -> - let formals = - formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in - let method_annotation = - JAnnotation.translate_method proc_name cm.Javalib.cm_annotations in - let proc_attributes = - { (ProcAttributes.default proc_name Config.Java) with - ProcAttributes.access = trans_access cm.Javalib.cm_access; - exceptions = IList.map JBasics.cn_name cm.Javalib.cm_exceptions; - formals; - is_bridge_method = cm.Javalib.cm_bridge; - is_synthetic_method = cm.Javalib.cm_synthetic; - method_annotation; - ret_type = JTransType.return_type program tenv ms; - } in - Cfg.create_proc_desc cfg proc_attributes; - | Javalib.ConcreteMethod cm -> - let impl = get_implementation cm in - let locals, formals = locals_formals program tenv cn impl in - let loc_start = - let loc = get_location source_file impl 0 in - fix_method_definition_line linereader proc_name loc in - let loc_exit = - get_location source_file impl (Array.length (JBir.code impl) - 1) in - let method_annotation = - JAnnotation.translate_method proc_name cm.Javalib.cm_annotations in - update_constr_loc cn ms loc_start; - update_init_loc cn ms loc_exit; - let proc_attributes = - { (ProcAttributes.default proc_name Config.Java) with - ProcAttributes.access = trans_access cm.Javalib.cm_access; - exceptions = IList.map JBasics.cn_name cm.Javalib.cm_exceptions; - formals; - is_bridge_method = cm.Javalib.cm_bridge; - is_defined = true; - is_synthetic_method = cm.Javalib.cm_synthetic; - is_java_synchronized_method = cm.Javalib.cm_synchronized; - loc = loc_start; - locals; - method_annotation; - ret_type = JTransType.return_type program tenv ms; - } in - let procdesc = - Cfg.create_proc_desc cfg proc_attributes in - let start_kind = Cfg.Node.Start_node proc_name in - let start_node = Cfg.Procdesc.create_node procdesc loc_start start_kind [] in - let exit_kind = (Cfg.Node.Exit_node proc_name) in - let exit_node = Cfg.Procdesc.create_node procdesc loc_exit exit_kind [] in - let exn_kind = Cfg.Node.exn_sink_kind in - let exn_node = Cfg.Procdesc.create_node procdesc loc_exit exn_kind [] in - JContext.add_exn_node proc_name exn_node; - Cfg.Procdesc.set_start_node procdesc start_node; - Cfg.Procdesc.set_exit_node procdesc exit_node; - Cfg.Node.add_locals_ret_declaration start_node proc_attributes locals; - procdesc in - Some procdesc - with JBir.Subroutine | JBasics.Class_structure_error _ -> + let locals, formals = locals_formals program tenv cn impl in + let loc_start = + let loc = get_location source_file impl 0 in + fix_method_definition_line linereader proc_name loc in + let loc_exit = + get_location source_file impl (Array.length (JBir.code impl) - 1) in + let method_annotation = + JAnnotation.translate_method proc_name cm.Javalib.cm_annotations in + update_constr_loc cn ms loc_start; + update_init_loc cn ms loc_exit; + let proc_attributes = + { (ProcAttributes.default proc_name Config.Java) with + ProcAttributes.access = trans_access cm.Javalib.cm_access; + exceptions = IList.map JBasics.cn_name cm.Javalib.cm_exceptions; + formals; + is_bridge_method = cm.Javalib.cm_bridge; + is_defined = true; + is_synthetic_method = cm.Javalib.cm_synthetic; + is_java_synchronized_method = cm.Javalib.cm_synchronized; + loc = loc_start; + locals; + method_annotation; + ret_type = JTransType.return_type program tenv ms; + } in + let procdesc = + Cfg.create_proc_desc cfg proc_attributes in + let start_kind = Cfg.Node.Start_node proc_name in + let start_node = Cfg.Procdesc.create_node procdesc loc_start start_kind [] in + let exit_kind = (Cfg.Node.Exit_node proc_name) in + let exit_node = Cfg.Procdesc.create_node procdesc loc_exit exit_kind [] in + let exn_kind = Cfg.Node.exn_sink_kind in + let exn_node = Cfg.Procdesc.create_node procdesc loc_exit exn_kind [] in + JContext.add_exn_node proc_name exn_node; + Cfg.Procdesc.set_start_node procdesc start_node; + Cfg.Procdesc.set_exit_node procdesc exit_node; + Cfg.Node.add_locals_ret_declaration start_node proc_attributes locals; + procdesc in + Some (procdesc, impl) + with JBir.Subroutine -> L.do_err - "create_procdesc raised JBir.Subroutine or JBasics.Class_structure_error on %a@." + "create_procdesc raised JBir.Subroutine on %a@." Procname.pp proc_name; None diff --git a/infer/src/java/jTrans.mli b/infer/src/java/jTrans.mli index 7eca6ad86..bfc4867aa 100644 --- a/infer/src/java/jTrans.mli +++ b/infer/src/java/jTrans.mli @@ -22,18 +22,28 @@ type translation = val is_java_native : JCode.jcode Javalib.concrete_method -> bool -(** [create_procdesc linereader cfg tenv program m] creates a procedure description - for the method m and adds it to cfg *) -val create_procdesc : +(** Create the procedure description for an abstract method *) +val create_am_procdesc : + JClasspath.program -> JContext.icfg -> Javalib.abstract_method -> Procname.t -> Cfg.Procdesc.t + +(** Create the procedure description for a concrete method *) +val create_native_procdesc : + JClasspath.program -> + JContext.icfg -> + JCode.jcode Javalib.concrete_method -> + Procname.t -> + Cfg.Procdesc.t + +(** [create_procdesc source_file program linereader icfg cm proc_name] creates + a procedure description for the concrete method cm and adds it to cfg *) +val create_cm_procdesc : DB.source_file -> JClasspath.program -> Printer.LineReader.t -> JContext.icfg -> - JCode.jcode Javalib.jmethod -> - Cfg.Procdesc.t option - -(** returns the implementation of a given method *) -val get_implementation : JCode.jcode Javalib.concrete_method -> JBir.t + JCode.jcode Javalib.concrete_method -> + Procname.t -> + (Cfg.Procdesc.t * JBir.t) option (** translates an instruction into a statement node or prune nodes in the cfg *) val instruction : JContext.t -> int -> JBir.instr -> translation