[infer][java] Translate the local variables directly from the bytecode

Summary:
Translate local variable names using the bytecode directly instead of JBir. The bytecode has more precise type information.

We still need to declare the temporary variables intruduced by Sawja until we can base the translation directly on the bytecode.

Reviewed By: sblackshear

Differential Revision: D4185309

fbshipit-source-id: 81904a0
master
Jeremy Dubreil 8 years ago committed by Facebook Github Bot
parent 90f3712555
commit ba62932760

@ -79,7 +79,7 @@ let add_cmethod source_file program linereader icfg cm proc_name =
let cn, _ = JBasics.cms_split cm.Javalib.cm_class_method_signature in let cn, _ = JBasics.cms_split cm.Javalib.cm_class_method_signature in
match JTrans.create_cm_procdesc source_file program linereader icfg cm proc_name with match JTrans.create_cm_procdesc source_file program linereader icfg cm proc_name with
| None -> () | None -> ()
| Some (procdesc, impl) -> | Some (procdesc, _, jbir_code) ->
let start_node = Procdesc.get_start_node procdesc in let start_node = Procdesc.get_start_node procdesc in
let exit_node = Procdesc.get_exit_node procdesc in let exit_node = Procdesc.get_exit_node procdesc in
let exn_node = let exn_node =
@ -87,11 +87,11 @@ let add_cmethod source_file program linereader icfg cm proc_name =
| Some node -> node | Some node -> node
| None -> | None ->
failwithf "No exn node found for %s" (Procname.to_string proc_name) in failwithf "No exn node found for %s" (Procname.to_string proc_name) in
let instrs = JBir.code impl in let instrs = JBir.code jbir_code in
let context = let context =
JContext.create_context icfg procdesc impl cn source_file program in JContext.create_context icfg procdesc jbir_code cn source_file program in
let method_body_nodes = Array.mapi (JTrans.instruction context) instrs in let method_body_nodes = Array.mapi (JTrans.instruction context) instrs in
add_edges context start_node exn_node [exit_node] method_body_nodes impl false add_edges context start_node exn_node [exit_node] method_body_nodes jbir_code false
let path_of_cached_classname cn = let path_of_cached_classname cn =

@ -134,30 +134,50 @@ let formals_from_signature program tenv cn ms kind =
| Procname.Non_Static -> [(JConfig.this, JTransType.get_class_type program tenv cn)] in | Procname.Non_Static -> [(JConfig.this, JTransType.get_class_type program tenv cn)] in
IList.rev (IList.fold_left collect init_arg_list (JBasics.ms_args ms)) IList.rev (IList.fold_left collect init_arg_list (JBasics.ms_args ms))
let formals program tenv cn impl = (** Creates the list of formal variables from a procedure based on ... *)
let translate_formals program tenv cn impl =
let collect l (vt, var) = let collect l (vt, var) =
let name = Mangled.from_string (JBir.var_name_g var) in let name = Mangled.from_string (JBir.var_name_g var) in
let typ = JTransType.param_type program tenv cn var vt in let typ = JTransType.param_type program tenv cn var vt in
(name, typ):: l in (name, typ):: l in
IList.rev (IList.fold_left collect [] (JBir.params impl)) IList.rev (IList.fold_left collect [] (JBir.params impl))
(** Creates the local and formal variables from a procedure based on the (** Creates the list of local variables from the bytecode and add the variables from
impl argument. If the meth_kind is Init, we add a parameter field to the JBir representation *)
the initialiser method. *) let translate_locals program tenv formals bytecode jbir_code =
let locals_formals program tenv cn impl = let formal_set =
let form_list = formals program tenv cn impl in IList.fold_left
let is_formal p = (fun set (var, _) -> Mangled.MangledSet.add var set)
IList.exists (fun (p', _) -> Mangled.equal p p') form_list in Mangled.MangledSet.empty
let collect l var = formals in
let vname = Mangled.from_string (JBir.var_name_g var) in let collect (seen_vars, l) (var, typ) =
let names = (fst (IList.split l)) in if Mangled.MangledSet.mem var seen_vars then
if not (is_formal vname) && (not (IList.mem Mangled.equal vname names)) then (seen_vars, l)
(vname, Typ.Tvoid):: l
else else
l in (Mangled.MangledSet.add var seen_vars, (var, typ) :: l) in
let vars = JBir.vars impl in let with_bytecode_vars =
let loc_list = IList.rev (Array.fold_left collect [] vars) in (* Do not consider parameters as local variables *)
(loc_list, form_list) let init = (formal_set, []) in
match bytecode.JCode.c_local_variable_table with
| None -> init
| Some variable_table ->
IList.fold_left
(fun accu (_, _, var_name, var_type, _) ->
let var = Mangled.from_string var_name
and typ = JTransType.value_type program tenv var_type in
collect accu (var, typ))
init
variable_table in
(* TODO (#4040807): Needs to add the JBir temporary variables since other parts of the
code are still relying on those *)
let with_jbir_vars =
Array.fold_left
(fun accu jbir_var ->
let var = Mangled.from_string (JBir.var_name_g jbir_var) in
collect accu (var, Typ.Tvoid))
with_bytecode_vars
(JBir.vars jbir_code) in
snd with_jbir_vars
let get_constant (c : JBir.const) = let get_constant (c : JBir.const) =
match c with match c with
@ -221,7 +241,7 @@ let get_implementation cm =
bytecode with this instruction. hack around this problem by converting all invokedynamic's bytecode with this instruction. hack around this problem by converting all invokedynamic's
to invokestatic's that call a method with the same signature as the lambda on to invokestatic's that call a method with the same signature as the lambda on
java.lang.Object. this isn't great, but it's a lot better than crashing *) java.lang.Object. this isn't great, but it's a lot better than crashing *)
let code = Lazy.force t in let bytecode = Lazy.force t in
let c_code = let c_code =
Array.map Array.map
(function (function
@ -229,9 +249,12 @@ let get_implementation cm =
JCode.OpInvoke (`Static JBasics.java_lang_object, ms) JCode.OpInvoke (`Static JBasics.java_lang_object, ms)
| opcode -> | opcode ->
opcode) opcode)
code.JCode.c_code in bytecode.JCode.c_code in
let code' = { code with JCode.c_code; } in let hacked_bytecode = { bytecode with JCode.c_code; } in
JBir.transform ~bcv: false ~ch_link: false ~formula: false ~formula_cmd:[] cm code' let jbir_code =
JBir.transform
~bcv: false ~ch_link: false ~formula: false ~formula_cmd:[] cm hacked_bytecode in
(hacked_bytecode, jbir_code)
let update_constr_loc cn ms loc_start = let update_constr_loc cn ms loc_start =
if (JBasics.ms_name ms) = JConfig.constructor_name then if (JBasics.ms_name ms) = JConfig.constructor_name then
@ -309,14 +332,15 @@ let create_cm_procdesc source_file program linereader icfg cm proc_name =
let m = Javalib.ConcreteMethod cm in let m = Javalib.ConcreteMethod cm in
let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in
try try
let impl = get_implementation cm in let bytecode, jbir_code = get_implementation cm in
let procdesc = let procdesc =
let locals, formals = locals_formals program tenv cn impl in let formals = translate_formals program tenv cn jbir_code in
let locals = translate_locals program tenv formals bytecode jbir_code in
let loc_start = let loc_start =
let loc = get_location source_file impl 0 in let loc = get_location source_file jbir_code 0 in
fix_method_definition_line linereader proc_name loc in fix_method_definition_line linereader proc_name loc in
let loc_exit = let loc_exit =
get_location source_file impl (Array.length (JBir.code impl) - 1) in get_location source_file jbir_code (Array.length (JBir.code jbir_code) - 1) in
let method_annotation = let method_annotation =
JAnnotation.translate_method proc_name cm.Javalib.cm_annotations in JAnnotation.translate_method proc_name cm.Javalib.cm_annotations in
update_constr_loc cn ms loc_start; update_constr_loc cn ms loc_start;
@ -348,7 +372,7 @@ let create_cm_procdesc source_file program linereader icfg cm proc_name =
Procdesc.set_exit_node procdesc exit_node; Procdesc.set_exit_node procdesc exit_node;
Procdesc.Node.add_locals_ret_declaration start_node proc_attributes locals; Procdesc.Node.add_locals_ret_declaration start_node proc_attributes locals;
procdesc in procdesc in
Some (procdesc, impl) Some (procdesc, bytecode, jbir_code)
with JBir.Subroutine -> with JBir.Subroutine ->
L.do_err L.do_err
"create_procdesc raised JBir.Subroutine on %a@." "create_procdesc raised JBir.Subroutine on %a@."

@ -43,7 +43,7 @@ val create_cm_procdesc :
JContext.icfg -> JContext.icfg ->
JCode.jcode Javalib.concrete_method -> JCode.jcode Javalib.concrete_method ->
Procname.t -> Procname.t ->
(Procdesc.t * JBir.t) option (Procdesc.t * Javalib_pack.JCode.jcode * JBir.t) option
(** translates an instruction into a statement node or prune nodes in the cfg *) (** translates an instruction into a statement node or prune nodes in the cfg *)
val instruction : JContext.t -> int -> JBir.instr -> translation val instruction : JContext.t -> int -> JBir.instr -> translation

Loading…
Cancel
Save