[clang] Translate structs on demand

Summary:
Instead of translating all structs/c++ classes and putting them into type environment, translate ones that are used. It now follows similar mechanism to ondemand function translation. This change should significantly decrease disk space/memory usage to store type environments

+ small change to fix build

Reviewed By: dulmarod

Differential Revision: D4597723

fbshipit-source-id: c8b0365
master
Andrzej Kotulski 8 years ago committed by Facebook Github Bot
parent 41c5be9bad
commit c7abd82d44

@ -1 +1 @@
Subproject commit 476112cbc79aa320afdb4dbf46b79c21432b4717 Subproject commit d05b658cc7b6d71268225a4d823b79640d83796a

@ -564,8 +564,8 @@ let pp_variable_list fmt etl =>
if (List.is_empty etl) { if (List.is_empty etl) {
Format.fprintf fmt "None" Format.fprintf fmt "None"
} else { } else {
IList.iter List.iter
(fun (id, ty) => Format.fprintf fmt " %a:%a" Mangled.pp id (Typ.pp_full Pp.text) ty) etl f::(fun (id, ty) => Format.fprintf fmt " %a:%a" Mangled.pp id (Typ.pp_full Pp.text) ty) etl
}; };
let pp_signature fmt pdesc => { let pp_signature fmt pdesc => {

@ -136,6 +136,17 @@ let get_translate_as_friend_decl decl_list =
| _ -> None | _ -> None
| exception Not_found -> None | exception Not_found -> None
let get_record_definition decl =
let open Clang_ast_t in
match decl with
| ClassTemplateSpecializationDecl
(_, _, _, _, _, _, {rdi_is_complete_definition; rdi_definition_ptr}, _, _)
| CXXRecordDecl (_, _, _, _, _, _, {rdi_is_complete_definition; rdi_definition_ptr}, _)
| RecordDecl (_, _, _, _, _, _, {rdi_is_complete_definition; rdi_definition_ptr})
when not rdi_is_complete_definition && rdi_definition_ptr <> 0 ->
CAst_utils.get_decl rdi_definition_ptr |> Option.value ~default:decl
| _ -> decl
let rec get_struct_fields tenv decl = let rec get_struct_fields tenv decl =
let open Clang_ast_t in let open Clang_ast_t in
let decl_list = match decl with let decl_list = match decl with
@ -156,56 +167,56 @@ let rec get_struct_fields tenv decl =
(* For a record declaration it returns/constructs the type *) (* For a record declaration it returns/constructs the type *)
and get_record_declaration_type tenv decl = and get_record_declaration_type tenv decl =
match get_record_custom_type tenv decl with let definition_decl = get_record_definition decl in
match get_record_custom_type tenv definition_decl with
| Some t -> t | Some t -> t
| None -> get_record_declaration_struct_type tenv decl | None -> get_record_struct_type tenv definition_decl
and get_record_custom_type tenv decl = and get_record_custom_type tenv definition_decl =
let open Clang_ast_t in let open Clang_ast_t in
match decl with match definition_decl with
| ClassTemplateSpecializationDecl (_, _, _, _, decl_list, _, _, _, _) | ClassTemplateSpecializationDecl (_, _, _, _, decl_list, _, _, _, _)
| CXXRecordDecl (_, _, _, _, decl_list, _, _, _) -> | CXXRecordDecl (_, _, _, _, decl_list, _, _, _) ->
Option.map ~f:(type_ptr_to_sil_type tenv) (get_translate_as_friend_decl decl_list) Option.map ~f:(type_ptr_to_sil_type tenv) (get_translate_as_friend_decl decl_list)
| _ -> None | _ -> None
and get_record_declaration_struct_type tenv decl = and get_record_struct_type tenv definition_decl =
let open Clang_ast_t in let open Clang_ast_t in
match decl with match definition_decl with
| ClassTemplateSpecializationDecl (_, _, _, type_ptr, decl_list, _, record_decl_info, _, _) | ClassTemplateSpecializationDecl (_, _, _, type_ptr, decl_list, _, record_decl_info, _, _)
| CXXRecordDecl (_, _, _, type_ptr, decl_list, _, record_decl_info, _) | CXXRecordDecl (_, _, _, type_ptr, decl_list, _, record_decl_info, _)
| RecordDecl (_, _, _, type_ptr, decl_list, _, record_decl_info) -> | RecordDecl (_, _, _, type_ptr, decl_list, _, record_decl_info) ->
let csu, name = get_record_name_csu decl in let csu, name = get_record_name_csu definition_decl in
let mangled_name = Mangled.from_string name in let mangled_name = Mangled.from_string name in
let is_complete_definition = record_decl_info.Clang_ast_t.rdi_is_complete_definition in
let sil_typename = Typename.TN_csu (csu, mangled_name) in let sil_typename = Typename.TN_csu (csu, mangled_name) in
let extra_fields = if CTrans_models.is_objc_memory_model_controlled name then (match Tenv.lookup tenv sil_typename with
[StructTyp.objc_ref_counter_field] | Some _ -> Typ.Tstruct sil_typename (* just reuse what is already in tenv *)
else [] in | None ->
let annots = let is_complete_definition = record_decl_info.Clang_ast_t.rdi_is_complete_definition in
if Csu.equal csu (Csu.Class Csu.CPP) then Annot.Class.cpp let extra_fields = if CTrans_models.is_objc_memory_model_controlled name then
else Annot.Item.empty (* No annotations for structs *) in [StructTyp.objc_ref_counter_field]
if is_complete_definition then ( else [] in
CAst_utils.update_sil_types_map type_ptr (Typ.Tstruct sil_typename); let annots =
let non_statics = get_struct_fields tenv decl in if Csu.equal csu (Csu.Class Csu.CPP) then Annot.Class.cpp
let fields = CGeneral_utils.append_no_duplicates_fields non_statics extra_fields in else Annot.Item.empty (* No annotations for structs *) in
let statics = [] in (* Note: We treat static field same as global variables *) if is_complete_definition then (
let methods = get_class_methods name decl_list in (* C++ methods only *) CAst_utils.update_sil_types_map type_ptr (Typ.Tstruct sil_typename);
let supers = get_superclass_list_cpp decl in let non_statics = get_struct_fields tenv definition_decl in
ignore (Tenv.mk_struct tenv ~fields ~statics ~methods ~supers ~annots sil_typename); let fields = CGeneral_utils.append_no_duplicates_fields non_statics extra_fields in
let sil_type = Typ.Tstruct sil_typename in let statics = [] in (* Note: We treat static field same as global variables *)
CAst_utils.update_sil_types_map type_ptr sil_type; let methods = get_class_methods name decl_list in (* C++ methods only *)
sil_type let supers = get_superclass_list_cpp definition_decl in
) else ( ignore (Tenv.mk_struct tenv ~fields ~statics ~methods ~supers ~annots sil_typename);
match Tenv.lookup tenv sil_typename with let sil_type = Typ.Tstruct sil_typename in
| Some _ -> Typ.Tstruct sil_typename (* just reuse what is already in tenv *) CAst_utils.update_sil_types_map type_ptr sil_type;
| None -> sil_type
(* This is first forward declaration seen. Add Tstruct to sil_types_map and struct with ) else (
only ref counter field to tenv. Later, when we see the definition, the tenv will be (* There is no definition for that struct in whole translation unit.
updated with a new struct including the other fields. *) Put empty struct into tenv to prevent backend problems *)
ignore (Tenv.mk_struct tenv ~fields:extra_fields sil_typename); ignore (Tenv.mk_struct tenv ~fields:extra_fields sil_typename);
let tvar_type = Typ.Tstruct sil_typename in let tvar_type = Typ.Tstruct sil_typename in
CAst_utils.update_sil_types_map type_ptr tvar_type; CAst_utils.update_sil_types_map type_ptr tvar_type;
tvar_type) tvar_type))
| _ -> assert false | _ -> assert false
and add_types_from_decl_to_tenv tenv decl = and add_types_from_decl_to_tenv tenv decl =

@ -179,7 +179,7 @@ struct
(* each procedure has different scope: start names from id 0 *) (* each procedure has different scope: start names from id 0 *)
Ident.NameGenerator.reset (); Ident.NameGenerator.reset ();
let translate = translate_one_declaration trans_unit_ctx tenv cg cfg decl_trans_context in
(if should_translate_decl trans_unit_ctx dec decl_trans_context then (if should_translate_decl trans_unit_ctx dec decl_trans_context then
match dec with match dec with
| FunctionDecl(_, _, _, _) -> | FunctionDecl(_, _, _, _) ->
@ -252,26 +252,24 @@ struct
ignore (CMethod_trans.create_local_procdesc trans_unit_ctx cfg tenv ms [body] [] false); ignore (CMethod_trans.create_local_procdesc trans_unit_ctx cfg tenv ms [body] [] false);
add_method trans_unit_ctx tenv cg cfg CContext.ContextNoCls procname body None false add_method trans_unit_ctx tenv cg cfg CContext.ContextNoCls procname body None false
None [] None []
(* Note that C and C++ records are treated the same way
Skip translating implicit struct declarations, unless they have
full definition (which happens with C++ lambdas) *)
| ClassTemplateSpecializationDecl (di, _, _, _, decl_list, _, rdi, _, _)
| CXXRecordDecl (di, _, _, _, decl_list, _, rdi, _)
| RecordDecl (di, _, _, _, decl_list, _, rdi)
when (not di.di_is_implicit) || rdi.rdi_is_complete_definition ->
let is_method_decl decl = match decl with
| CXXMethodDecl _ | CXXConstructorDecl _ | CXXConversionDecl _
| CXXDestructorDecl _ | FunctionTemplateDecl _ ->
true
| _ -> false in
let method_decls, no_method_decls = IList.partition is_method_decl decl_list in
List.iter ~f:translate no_method_decls;
ignore (CType_decl.add_types_from_decl_to_tenv tenv dec);
List.iter ~f:translate method_decls
| _ -> ()); | _ -> ());
let translate = translate_one_declaration trans_unit_ctx tenv cg cfg decl_trans_context in
match dec with match dec with
(* Note that C and C++ records are treated the same way
Skip translating implicit struct declarations, unless they have
full definition (which happens with C++ lambdas) *)
| ClassTemplateSpecializationDecl (di, _, _, _, decl_list, _, rdi, _, _)
| CXXRecordDecl (di, _, _, _, decl_list, _, rdi, _)
| RecordDecl (di, _, _, _, decl_list, _, rdi)
when (not di.di_is_implicit) || rdi.rdi_is_complete_definition ->
let is_method_decl decl = match decl with
| CXXMethodDecl _ | CXXConstructorDecl _ | CXXConversionDecl _
| CXXDestructorDecl _ | FunctionTemplateDecl _ ->
true
| _ -> false in
let method_decls, no_method_decls = IList.partition is_method_decl decl_list in
List.iter ~f:translate no_method_decls;
ignore (CType_decl.add_types_from_decl_to_tenv tenv dec);
List.iter ~f:translate method_decls
| EnumDecl _ -> ignore (CEnum_decl.enum_decl dec) | EnumDecl _ -> ignore (CEnum_decl.enum_decl dec)
| LinkageSpecDecl (_, decl_list, _) -> | LinkageSpecDecl (_, decl_list, _) ->
Logging.out_debug "ADDING: LinkageSpecDecl decl list@\n"; Logging.out_debug "ADDING: LinkageSpecDecl decl list@\n";

Loading…
Cancel
Save