[clang] cache of names of C++ temporaries

Summary:
Needed for next diff: we'll need to do 2 passes on the AST to collect
the temporaries to destroy at the end of an `ExprWithCleanups`, but the
SIL names of these temporaries are generated freshly on the fly so they
would get different names if we do it naively.

This adds a hashmap to the translation context so the temporary
corresponding to a given `MaterializeTemporyExpr` is only generated once
and then reused.

Reviewed By: mbouaziz

Differential Revision: D15674212

fbshipit-source-id: 0e16062d9
master
Jules Villard 6 years ago committed by Facebook Github Bot
parent a9a7239831
commit ab427fd3f3

@ -7,16 +7,9 @@
open! IStd open! IStd
module Hashtbl = Caml.Hashtbl module Hashtbl = Caml.Hashtbl
(** Contains current class and current method to be translated as well as local variables, *)
(** and the cg, cfg, and tenv corresponding to the current file. *)
module StmtMap = ClangPointers.Map module StmtMap = ClangPointers.Map
type pointer = int [@@deriving compare] type pointer = (* = Clang_ast_t.pointer *) int [@@deriving compare]
(* = Clang_ast_t.pointer *)
type curr_class = ContextClsDeclPtr of pointer | ContextNoCls [@@deriving compare] type curr_class = ContextClsDeclPtr of pointer | ContextNoCls [@@deriving compare]
@ -32,7 +25,8 @@ type t =
; outer_context: t option ; outer_context: t option
; mutable blocks_static_vars: (Pvar.t * Typ.t) list Typ.Procname.Map.t ; mutable blocks_static_vars: (Pvar.t * Typ.t) list Typ.Procname.Map.t
; label_map: str_node_map ; label_map: str_node_map
; vars_to_destroy: Clang_ast_t.decl list StmtMap.t } ; vars_to_destroy: Clang_ast_t.decl list StmtMap.t
; temporary_names: (Clang_ast_t.pointer, Pvar.t * Typ.t) Hashtbl.t }
let create_context translation_unit_context tenv cfg procdesc immediate_curr_class return_param_typ let create_context translation_unit_context tenv cfg procdesc immediate_curr_class return_param_typ
outer_context vars_to_destroy = outer_context vars_to_destroy =
@ -45,7 +39,8 @@ let create_context translation_unit_context tenv cfg procdesc immediate_curr_cla
; outer_context ; outer_context
; blocks_static_vars= Typ.Procname.Map.empty ; blocks_static_vars= Typ.Procname.Map.empty
; label_map= Hashtbl.create 17 ; label_map= Hashtbl.create 17
; vars_to_destroy } ; vars_to_destroy
; temporary_names= Hashtbl.create 0 }
let rec is_objc_method context = let rec is_objc_method context =

@ -7,9 +7,8 @@
open! IStd open! IStd
(** Contains current class and current method to be translated as well as local variables, *) (** Contains current class and current method to be translated as well as local variables,
and the cfg, and tenv corresponding to the current file. *)
(** and the cg, cfg, and tenv corresponding to the current file. *)
module StmtMap = ClangPointers.Map module StmtMap = ClangPointers.Map
@ -29,9 +28,9 @@ type t =
; mutable blocks_static_vars: (Pvar.t * Typ.t) list Typ.Procname.Map.t ; mutable blocks_static_vars: (Pvar.t * Typ.t) list Typ.Procname.Map.t
; label_map: str_node_map ; label_map: str_node_map
; vars_to_destroy: Clang_ast_t.decl list StmtMap.t ; vars_to_destroy: Clang_ast_t.decl list StmtMap.t
(** mapping from a statement to a list of variables, that go out of scope after the end of the (** mapping from a statement to a list of variables, that go out of scope after the end of
statement *) the statement *)
} ; temporary_names: (Clang_ast_t.pointer, Pvar.t * Typ.t) Caml.Hashtbl.t }
val get_curr_class : t -> curr_class val get_curr_class : t -> curr_class

@ -195,21 +195,12 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
Ident.NameGenerator.set_current ident_state Ident.NameGenerator.set_current ident_state
let mk_temp_sil_var procdesc var_name_suffix = let create_var_exp_tmp_var trans_state expr_info ~clang_pointer ~var_name =
let procname = Procdesc.get_proc_name procdesc in
Pvar.mk_tmp var_name_suffix procname
let mk_temp_sil_var_for_expr tenv procdesc var_name_prefix expr_info =
let qual_type = expr_info.Clang_ast_t.ei_qual_type in
let typ = CType_decl.qual_type_to_sil_type tenv qual_type in
(mk_temp_sil_var procdesc var_name_prefix, typ)
let create_var_exp_tmp_var trans_state expr_info var_name =
let context = trans_state.context in let context = trans_state.context in
let procdesc = context.CContext.procdesc in let procdesc = context.CContext.procdesc in
let pvar, typ = mk_temp_sil_var_for_expr context.CContext.tenv procdesc var_name expr_info in let pvar, typ =
CVar_decl.mk_temp_sil_var_for_expr context ~name:var_name ~clang_pointer expr_info
in
let var_data = let var_data =
ProcAttributes.{name= Pvar.get_name pvar; typ; modify_in_block= false; is_constexpr= false} ProcAttributes.{name= Pvar.get_name pvar; typ; modify_in_block= false; is_constexpr= false}
in in
@ -246,7 +237,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
exp exp
| _ -> | _ ->
let procdesc = trans_state.context.CContext.procdesc in let procdesc = trans_state.context.CContext.procdesc in
let pvar = mk_temp_sil_var procdesc "__temp_return_" in let pvar = CVar_decl.mk_temp_sil_var procdesc ~name:"__temp_return_" in
let var_data : ProcAttributes.var_data = let var_data : ProcAttributes.var_data =
{ name= Pvar.get_name pvar { name= Pvar.get_name pvar
; typ= return_type ; typ= return_type
@ -1541,7 +1532,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
Procdesc.Node.Join_node [] Procdesc.Node.Join_node []
in in
Procdesc.node_set_succs_exn context.procdesc join_node succ_nodes [] ; Procdesc.node_set_succs_exn context.procdesc join_node succ_nodes [] ;
let pvar = mk_temp_sil_var procdesc "SIL_temp_conditional___" in let pvar = CVar_decl.mk_temp_sil_var procdesc ~name:"SIL_temp_conditional___" in
let var_data = let var_data =
ProcAttributes. ProcAttributes.
{name= Pvar.get_name pvar; typ= var_typ; modify_in_block= false; is_constexpr= false} {name= Pvar.get_name pvar; typ= var_typ; modify_in_block= false; is_constexpr= false}
@ -2204,7 +2195,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
| Some var_exp_typ -> | Some var_exp_typ ->
var_exp_typ var_exp_typ
| None -> | None ->
create_var_exp_tmp_var trans_state expr_info "SIL_init_list__" create_var_exp_tmp_var trans_state expr_info ~var_name:"SIL_init_list__"
~clang_pointer:stmt_info.Clang_ast_t.si_pointer
in in
if List.is_empty stmts then if List.is_empty stmts then
(* perform zero initialization of a primitive type, record types will have (* perform zero initialization of a primitive type, record types will have
@ -2985,12 +2977,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
and materializeTemporaryExpr_trans trans_state stmt_info stmt_list expr_info = and materializeTemporaryExpr_trans trans_state stmt_info stmt_list expr_info =
let context = trans_state.context in let context = trans_state.context in
let procdesc = context.CContext.procdesc in let procdesc = context.CContext.procdesc in
(* typ_tmp is 'best guess' type of variable - translation may decide to use different type let pvar, typ_tmp = CVar_decl.materialize_cpp_temporary context stmt_info expr_info in
later *)
let pvar, typ_tmp =
mk_temp_sil_var_for_expr context.CContext.tenv procdesc Pvar.materialized_cpp_temporary
expr_info
in
let temp_exp = match stmt_list with [p] -> p | _ -> assert false in let temp_exp = match stmt_list with [p] -> p | _ -> assert false in
let var_exp_typ = (Exp.Lvar pvar, typ_tmp) in let var_exp_typ = (Exp.Lvar pvar, typ_tmp) in
let res_trans = init_expr_trans trans_state var_exp_typ stmt_info (Some temp_exp) in let res_trans = init_expr_trans trans_state var_exp_typ stmt_info (Some temp_exp) in
@ -3002,11 +2989,14 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
res_trans res_trans
and compoundLiteralExpr_trans trans_state stmt_list expr_info = and compoundLiteralExpr_trans trans_state stmt_list stmt_info expr_info =
let stmt = match stmt_list with [stmt] -> stmt | _ -> assert false in let stmt = match stmt_list with [stmt] -> stmt | _ -> assert false in
let var_exp_typ = let var_exp_typ =
if Option.is_some trans_state.var_exp_typ then trans_state.var_exp_typ if Option.is_some trans_state.var_exp_typ then trans_state.var_exp_typ
else Some (create_var_exp_tmp_var trans_state expr_info "SIL_compound_literal__") else
Some
(create_var_exp_tmp_var trans_state expr_info ~var_name:"SIL_compound_literal__"
~clang_pointer:stmt_info.Clang_ast_t.si_pointer)
in in
let trans_state' = {trans_state with var_exp_typ} in let trans_state' = {trans_state with var_exp_typ} in
instruction trans_state' stmt instruction trans_state' stmt
@ -3523,8 +3513,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
cxxDeleteExpr_trans trans_state stmt_info stmt_list delete_expr_info cxxDeleteExpr_trans trans_state stmt_info stmt_list delete_expr_info
| MaterializeTemporaryExpr (stmt_info, stmt_list, expr_info, _) -> | MaterializeTemporaryExpr (stmt_info, stmt_list, expr_info, _) ->
materializeTemporaryExpr_trans trans_state stmt_info stmt_list expr_info materializeTemporaryExpr_trans trans_state stmt_info stmt_list expr_info
| CompoundLiteralExpr (_, stmt_list, expr_info) -> | CompoundLiteralExpr (stmt_info, stmt_list, expr_info) ->
compoundLiteralExpr_trans trans_state stmt_list expr_info compoundLiteralExpr_trans trans_state stmt_list stmt_info expr_info
| InitListExpr (stmt_info, stmts, expr_info) -> | InitListExpr (stmt_info, stmts, expr_info) ->
initListExpr_trans trans_state stmt_info expr_info stmts initListExpr_trans trans_state stmt_info expr_info stmts
| CXXBindTemporaryExpr ({Clang_ast_t.si_source_range}, stmt_list, _, _) -> | CXXBindTemporaryExpr ({Clang_ast_t.si_source_range}, stmt_list, _, _) ->

@ -118,3 +118,27 @@ let captured_vars_from_block_info context source_range captured_vars =
List.map ~f:(fun cv -> Option.value_exn cv.Clang_ast_t.bcv_variable) captured_vars List.map ~f:(fun cv -> Option.value_exn cv.Clang_ast_t.bcv_variable) captured_vars
in in
List.filter_map ~f:(sil_var_of_captured_var context source_range procname) cv_decl_ref_list List.filter_map ~f:(sil_var_of_captured_var context source_range procname) cv_decl_ref_list
let mk_temp_sil_var procdesc ~name =
let procname = Procdesc.get_proc_name procdesc in
Pvar.mk_tmp name procname
let mk_temp_sil_var_for_expr context ~name ~clang_pointer expr_info =
match Caml.Hashtbl.find_opt context.CContext.temporary_names clang_pointer with
| Some pvar_typ ->
pvar_typ
| None ->
let qual_type = expr_info.Clang_ast_t.ei_qual_type in
let typ = CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type in
let pvar_typ = (mk_temp_sil_var context.CContext.procdesc ~name, typ) in
Caml.Hashtbl.add context.CContext.temporary_names clang_pointer pvar_typ ;
pvar_typ
let materialize_cpp_temporary context stmt_info expr_info =
(* the type we get here is a 'best effort' type - the translation may decide to use different type
later *)
mk_temp_sil_var_for_expr context ~name:Pvar.materialized_cpp_temporary
~clang_pointer:stmt_info.Clang_ast_t.si_pointer expr_info

@ -30,3 +30,11 @@ val captured_vars_from_block_info :
-> Clang_ast_t.source_range -> Clang_ast_t.source_range
-> Clang_ast_t.block_captured_variable list -> Clang_ast_t.block_captured_variable list
-> (Pvar.t * Typ.t) list -> (Pvar.t * Typ.t) list
val mk_temp_sil_var : Procdesc.t -> name:string -> Pvar.t
val mk_temp_sil_var_for_expr :
CContext.t -> name:string -> clang_pointer:int -> Clang_ast_t.expr_info -> Pvar.t * Typ.t
val materialize_cpp_temporary :
CContext.t -> Clang_ast_t.stmt_info -> Clang_ast_t.expr_info -> Pvar.t * Typ.t

Loading…
Cancel
Save