| /* modules.cc -- D module initialization and termination. |
| Copyright (C) 2013-2021 Free Software Foundation, Inc. |
| |
| GCC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| |
| #include "dmd/declaration.h" |
| #include "dmd/identifier.h" |
| #include "dmd/module.h" |
| |
| #include "tree.h" |
| #include "diagnostic.h" |
| #include "fold-const.h" |
| #include "tm.h" |
| #include "function.h" |
| #include "cgraph.h" |
| #include "stor-layout.h" |
| #include "toplev.h" |
| #include "target.h" |
| #include "common/common-target.h" |
| #include "stringpool.h" |
| |
| #include "d-tree.h" |
| #include "d-target.h" |
| |
| |
| /* D generates module information to inform the runtime library which modules |
| need some kind of special handling. All `static this()', `static ~this()', |
| and `unittest' functions for a given module are aggregated into a single |
| function - one for each kind - and a pointer to that function is inserted |
| into the ModuleInfo instance for that module. |
| |
| Module information for a particular module is indicated with an ABI defined |
| structure derived from ModuleInfo. ModuleInfo is a variably sized struct |
| with two fixed base fields. The first field `flags' determines what |
| information is packed immediately after the record type. |
| |
| Like TypeInfo, the runtime library provides the definitions of the ModuleInfo |
| structure, as well as accessors for the variadic fields. So we only define |
| layout compatible POD_structs for ModuleInfo. */ |
| |
| /* The internally represented ModuleInfo and CompilerDSO types. */ |
| static tree moduleinfo_type; |
| static tree compiler_dso_type; |
| static tree dso_registry_fn; |
| |
| /* The DSO slot for use by the druntime implementation. */ |
| static tree dso_slot_node; |
| |
| /* For registering and deregistering DSOs with druntime, we have one global |
| constructor and destructor per object that calls _d_dso_registry with the |
| respective DSO record. To ensure that this is only done once, a |
| `dso_initialized' variable is introduced to guard repeated calls. */ |
| static tree dso_initialized_node; |
| |
| /* The beginning and end of the `minfo' section. */ |
| static tree start_minfo_node; |
| static tree stop_minfo_node; |
| |
| /* Record information about module initialization, termination, |
| unit testing, and thread local storage in the compilation. */ |
| |
| struct module_info |
| { |
| vec <tree, va_gc> *ctors; |
| vec <tree, va_gc> *dtors; |
| vec <tree, va_gc> *ctorgates; |
| |
| vec <tree, va_gc> *sharedctors; |
| vec <tree, va_gc> *shareddtors; |
| vec <tree, va_gc> *sharedctorgates; |
| |
| vec <tree, va_gc> *unitTests; |
| }; |
| |
| /* These must match the values in libdruntime/object_.d. */ |
| |
| enum module_info_flags |
| { |
| MIctorstart = 0x1, |
| MIctordone = 0x2, |
| MIstandalone = 0x4, |
| MItlsctor = 0x8, |
| MItlsdtor = 0x10, |
| MIctor = 0x20, |
| MIdtor = 0x40, |
| MIxgetMembers = 0x80, |
| MIictor = 0x100, |
| MIunitTest = 0x200, |
| MIimportedModules = 0x400, |
| MIlocalClasses = 0x800, |
| MIname = 0x1000 |
| }; |
| |
| /* The ModuleInfo information structure for the module currently being compiled. |
| Assuming that only ever process one at a time. */ |
| |
| static module_info *current_moduleinfo; |
| |
| /* When compiling with -fbuilding-libphobos-tests, this contains information |
| about the module that gets compiled in only when unittests are enabled. */ |
| |
| static module_info *current_testing_module; |
| |
| /* The declaration of the current module being compiled. */ |
| |
| static Module *current_module_decl; |
| |
| /* Returns an internal function identified by IDENT. This is used |
| by both module initialization and dso handlers. */ |
| |
| static FuncDeclaration * |
| get_internal_fn (tree ident, const Prot &prot) |
| { |
| Module *mod = current_module_decl; |
| const char *name = IDENTIFIER_POINTER (ident); |
| |
| if (!mod) |
| mod = Module::rootModule; |
| |
| if (name[0] == '*') |
| { |
| tree s = mangle_internal_decl (mod, name + 1, "FZv"); |
| name = IDENTIFIER_POINTER (s); |
| } |
| |
| FuncDeclaration *fd = FuncDeclaration::genCfunc (NULL, Type::tvoid, |
| Identifier::idPool (name)); |
| fd->generated = true; |
| fd->loc = Loc (mod->srcfile->toChars (), 1, 0); |
| fd->parent = mod; |
| fd->protection = prot; |
| fd->semanticRun = PASSsemantic3done; |
| |
| return fd; |
| } |
| |
| /* Generate an internal function identified by IDENT. |
| The function body to add is in EXPR. */ |
| |
| static tree |
| build_internal_fn (tree ident, tree expr) |
| { |
| FuncDeclaration *fd = get_internal_fn (ident, Prot (Prot::private_)); |
| tree decl = get_symbol_decl (fd); |
| |
| tree old_context = start_function (fd); |
| rest_of_decl_compilation (decl, 1, 0); |
| add_stmt (expr); |
| finish_function (old_context); |
| |
| /* D static ctors, static dtors, unittests, and the ModuleInfo |
| chain function are always private. */ |
| TREE_PUBLIC (decl) = 0; |
| TREE_USED (decl) = 1; |
| DECL_ARTIFICIAL (decl) = 1; |
| |
| return decl; |
| } |
| |
| /* Build and emit a function identified by IDENT that increments (in order) |
| all variables in GATES, then calls the list of functions in FUNCTIONS. */ |
| |
| static tree |
| build_funcs_gates_fn (tree ident, vec <tree, va_gc> *functions, |
| vec <tree, va_gc> *gates) |
| { |
| tree expr_list = NULL_TREE; |
| |
| /* Increment gates first. */ |
| for (size_t i = 0; i < vec_safe_length (gates); i++) |
| { |
| tree decl = (*gates)[i]; |
| tree value = build2 (PLUS_EXPR, TREE_TYPE (decl), |
| decl, integer_one_node); |
| tree var_expr = modify_expr (decl, value); |
| expr_list = compound_expr (expr_list, var_expr); |
| } |
| |
| /* Call Functions. */ |
| for (size_t i = 0; i < vec_safe_length (functions); i++) |
| { |
| tree decl = (*functions)[i]; |
| tree call_expr = build_call_expr (decl, 0); |
| expr_list = compound_expr (expr_list, call_expr); |
| } |
| |
| if (expr_list) |
| return build_internal_fn (ident, expr_list); |
| |
| return NULL_TREE; |
| } |
| |
| /* Return the type for ModuleInfo, create it if it doesn't already exist. */ |
| |
| static tree |
| get_moduleinfo_type (void) |
| { |
| if (moduleinfo_type) |
| return moduleinfo_type; |
| |
| /* Layout of ModuleInfo is: |
| uint flags; |
| uint index; */ |
| tree fields = create_field_decl (d_uint_type, NULL, 1, 1); |
| DECL_CHAIN (fields) = create_field_decl (d_uint_type, NULL, 1, 1); |
| |
| moduleinfo_type = make_node (RECORD_TYPE); |
| finish_builtin_struct (moduleinfo_type, "ModuleInfo", fields, NULL_TREE); |
| |
| return moduleinfo_type; |
| } |
| |
| /* Get the VAR_DECL of the ModuleInfo for DECL. If this does not yet exist, |
| create it. The ModuleInfo decl is used to keep track of constructors, |
| destructors, unittests, members, classes, and imports for the given module. |
| This is used by the D runtime for module initialization and termination. */ |
| |
| static tree |
| get_moduleinfo_decl (Module *decl) |
| { |
| if (decl->csym) |
| return decl->csym; |
| |
| tree ident = mangle_internal_decl (decl, "__ModuleInfo", "Z"); |
| tree type = get_moduleinfo_type (); |
| |
| decl->csym = declare_extern_var (ident, type); |
| DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (NULL); |
| |
| DECL_CONTEXT (decl->csym) = build_import_decl (decl); |
| /* Not readonly, moduleinit depends on this. */ |
| TREE_READONLY (decl->csym) = 0; |
| |
| return decl->csym; |
| } |
| |
| /* Return the type for CompilerDSOData, create it if it doesn't exist. */ |
| |
| static tree |
| get_compiler_dso_type (void) |
| { |
| if (compiler_dso_type) |
| return compiler_dso_type; |
| |
| /* Layout of CompilerDSOData is: |
| size_t version; |
| void** slot; |
| ModuleInfo** _minfo_beg; |
| ModuleInfo** _minfo_end; |
| FuncTable* _deh_beg; |
| FuncTable* _deh_end; |
| |
| Note, finish_builtin_struct() expects these fields in reverse order. */ |
| tree fields = create_field_decl (ptr_type_node, NULL, 1, 1); |
| tree field = create_field_decl (ptr_type_node, NULL, 1, 1); |
| DECL_CHAIN (field) = fields; |
| fields = field; |
| |
| field = create_field_decl (build_pointer_type (get_moduleinfo_type ()), |
| NULL, 1, 1); |
| DECL_CHAIN (field) = fields; |
| fields = field; |
| field = create_field_decl (build_pointer_type (get_moduleinfo_type ()), |
| NULL, 1, 1); |
| DECL_CHAIN (field) = fields; |
| fields = field; |
| |
| field = create_field_decl (build_pointer_type (ptr_type_node), NULL, 1, 1); |
| DECL_CHAIN (field) = fields; |
| fields = field; |
| |
| field = create_field_decl (size_type_node, NULL, 1, 1); |
| DECL_CHAIN (field) = fields; |
| fields = field; |
| |
| compiler_dso_type = make_node (RECORD_TYPE); |
| finish_builtin_struct (compiler_dso_type, "CompilerDSOData", |
| fields, NULL_TREE); |
| |
| return compiler_dso_type; |
| } |
| |
| /* Returns the _d_dso_registry FUNCTION_DECL. */ |
| |
| static tree |
| get_dso_registry_fn (void) |
| { |
| if (dso_registry_fn) |
| return dso_registry_fn; |
| |
| tree dso_type = get_compiler_dso_type (); |
| tree fntype = build_function_type_list (void_type_node, |
| build_pointer_type (dso_type), |
| NULL_TREE); |
| dso_registry_fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, |
| get_identifier ("_d_dso_registry"), fntype); |
| TREE_PUBLIC (dso_registry_fn) = 1; |
| DECL_EXTERNAL (dso_registry_fn) = 1; |
| |
| return dso_registry_fn; |
| } |
| |
| /* Depending on CTOR_P, builds and emits eiter a constructor or destructor |
| calling _d_dso_registry if `dso_initialized' is `false' in a constructor |
| or `true' in a destructor. */ |
| |
| static tree |
| build_dso_cdtor_fn (bool ctor_p) |
| { |
| const char *name = ctor_p ? GDC_PREFIX ("dso_ctor") : GDC_PREFIX ("dso_dtor"); |
| tree condition = ctor_p ? boolean_true_node : boolean_false_node; |
| |
| /* Declaration of dso_ctor/dso_dtor is: |
| |
| extern(C) void dso_{c,d}tor (void) |
| { |
| if (dso_initialized != condition) |
| { |
| dso_initialized = condition; |
| CompilerDSOData dso = {1, &dsoSlot, &__start_minfo, &__stop_minfo}; |
| _d_dso_registry (&dso); |
| } |
| } |
| */ |
| FuncDeclaration *fd = get_internal_fn (get_identifier (name), |
| Prot (Prot::public_)); |
| tree decl = get_symbol_decl (fd); |
| |
| TREE_PUBLIC (decl) = 1; |
| DECL_ARTIFICIAL (decl) = 1; |
| DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; |
| DECL_VISIBILITY_SPECIFIED (decl) = 1; |
| |
| /* Start laying out the body. */ |
| tree old_context = start_function (fd); |
| rest_of_decl_compilation (decl, 1, 0); |
| |
| /* if (dso_initialized != condition). */ |
| tree if_cond = build_boolop (NE_EXPR, dso_initialized_node, condition); |
| |
| /* dso_initialized = condition; */ |
| tree expr_list = modify_expr (dso_initialized_node, condition); |
| |
| /* CompilerDSOData dso = {1, &dsoSlot, &__start_minfo, &__stop_minfo}; */ |
| tree dso_type = get_compiler_dso_type (); |
| tree dso = build_local_temp (dso_type); |
| |
| vec <constructor_elt, va_gc> *ve = NULL; |
| CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_integer_cst (1, size_type_node)); |
| CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (dso_slot_node)); |
| CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (start_minfo_node)); |
| CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (stop_minfo_node)); |
| |
| tree assign_expr = modify_expr (dso, build_struct_literal (dso_type, ve)); |
| expr_list = compound_expr (expr_list, assign_expr); |
| |
| /* _d_dso_registry (&dso); */ |
| tree call_expr = build_call_expr (get_dso_registry_fn (), 1, |
| build_address (dso)); |
| expr_list = compound_expr (expr_list, call_expr); |
| |
| add_stmt (build_vcondition (if_cond, expr_list, void_node)); |
| finish_function (old_context); |
| |
| return decl; |
| } |
| |
| /* Build a variable used in the dso_registry code identified by NAME, |
| and data type TYPE. The variable always has VISIBILITY_HIDDEN and |
| TREE_PUBLIC flags set. */ |
| |
| static tree |
| build_dso_registry_var (const char * name, tree type) |
| { |
| tree var = declare_extern_var (get_identifier (name), type); |
| DECL_VISIBILITY (var) = VISIBILITY_HIDDEN; |
| DECL_VISIBILITY_SPECIFIED (var) = 1; |
| return var; |
| } |
| |
| /* Place a reference to the ModuleInfo symbol MINFO for DECL into the |
| `minfo' section. Then create the global ctors/dtors to call the |
| _d_dso_registry function if necessary. */ |
| |
| static void |
| register_moduleinfo (Module *decl, tree minfo) |
| { |
| /* No defined minfo section for target. */ |
| if (targetdm.d_minfo_section == NULL) |
| return; |
| |
| if (!targetm_common.have_named_sections) |
| sorry ("%<-fmoduleinfo%> is not supported on this target"); |
| |
| /* Build the ModuleInfo reference, this is done once for every Module. */ |
| tree ident = mangle_internal_decl (decl, "__moduleRef", "Z"); |
| tree mref = declare_extern_var (ident, ptr_type_node); |
| |
| /* Build the initializer and emit. Do not start section with a `.' character |
| so that the linker will provide a __start_ and __stop_ symbol to indicate |
| the start and end address of the section respectively. |
| https://sourceware.org/binutils/docs-2.26/ld/Orphan-Sections.html. */ |
| DECL_INITIAL (mref) = build_address (minfo); |
| DECL_EXTERNAL (mref) = 0; |
| DECL_PRESERVE_P (mref) = 1; |
| |
| set_decl_section_name (mref, targetdm.d_minfo_section); |
| symtab_node::get (mref)->implicit_section = true; |
| d_pushdecl (mref); |
| rest_of_decl_compilation (mref, 1, 0); |
| |
| /* Only for the first D module being emitted do we need to generate a static |
| constructor and destructor for. These are only required once per shared |
| library, so it's safe to emit them only once per object file. */ |
| static bool first_module = true; |
| if (!first_module) |
| return; |
| |
| start_minfo_node = build_dso_registry_var (targetdm.d_minfo_start_name, |
| ptr_type_node); |
| rest_of_decl_compilation (start_minfo_node, 1, 0); |
| |
| stop_minfo_node = build_dso_registry_var (targetdm.d_minfo_end_name, |
| ptr_type_node); |
| rest_of_decl_compilation (stop_minfo_node, 1, 0); |
| |
| /* Declare dso_slot and dso_initialized. */ |
| dso_slot_node = build_dso_registry_var (GDC_PREFIX ("dso_slot"), |
| ptr_type_node); |
| d_finish_decl (dso_slot_node); |
| |
| dso_initialized_node = build_dso_registry_var (GDC_PREFIX ("dso_initialized"), |
| boolean_type_node); |
| d_finish_decl (dso_initialized_node); |
| |
| /* Declare dso_ctor() and dso_dtor(). */ |
| tree dso_ctor = build_dso_cdtor_fn (true); |
| DECL_STATIC_CONSTRUCTOR (dso_ctor) = 1; |
| decl_init_priority_insert (dso_ctor, DEFAULT_INIT_PRIORITY); |
| |
| tree dso_dtor = build_dso_cdtor_fn (false); |
| DECL_STATIC_DESTRUCTOR (dso_dtor) = 1; |
| decl_fini_priority_insert (dso_dtor, DEFAULT_INIT_PRIORITY); |
| |
| first_module = false; |
| } |
| |
| /* Convenience function for layout_moduleinfo_fields. Adds a field of TYPE to |
| the moduleinfo record at OFFSET, incrementing the offset to the next field |
| position. No alignment is taken into account, all fields are packed. */ |
| |
| static void |
| layout_moduleinfo_field (tree type, tree rec_type, HOST_WIDE_INT &offset) |
| { |
| tree field = create_field_decl (type, NULL, 1, 1); |
| insert_aggregate_field (rec_type, field, offset); |
| offset += int_size_in_bytes (type); |
| } |
| |
| /* Layout fields that immediately come after the moduleinfo TYPE for DECL. |
| Data relating to the module is packed into the type on an as-needed |
| basis, this is done to keep its size to a minimum. */ |
| |
| static tree |
| layout_moduleinfo_fields (Module *decl, tree type) |
| { |
| HOST_WIDE_INT offset = int_size_in_bytes (type); |
| type = copy_aggregate_type (type); |
| |
| /* First fields added are all the function pointers. */ |
| if (decl->sctor) |
| layout_moduleinfo_field (ptr_type_node, type, offset); |
| |
| if (decl->sdtor) |
| layout_moduleinfo_field (ptr_type_node, type, offset); |
| |
| if (decl->ssharedctor) |
| layout_moduleinfo_field (ptr_type_node, type, offset); |
| |
| if (decl->sshareddtor) |
| layout_moduleinfo_field (ptr_type_node, type, offset); |
| |
| if (decl->findGetMembers ()) |
| layout_moduleinfo_field (ptr_type_node, type, offset); |
| |
| if (decl->sictor) |
| layout_moduleinfo_field (ptr_type_node, type, offset); |
| |
| if (decl->stest) |
| layout_moduleinfo_field (ptr_type_node, type, offset); |
| |
| /* Array of module imports is laid out as a length field, followed by |
| a static array of ModuleInfo pointers. */ |
| size_t aimports_dim = decl->aimports.length; |
| for (size_t i = 0; i < decl->aimports.length; i++) |
| { |
| Module *mi = decl->aimports[i]; |
| if (!mi->needmoduleinfo) |
| aimports_dim--; |
| } |
| |
| if (aimports_dim) |
| { |
| layout_moduleinfo_field (size_type_node, type, offset); |
| layout_moduleinfo_field (make_array_type (Type::tvoidptr, aimports_dim), |
| type, offset); |
| } |
| |
| /* Array of local ClassInfo decls are laid out in the same way. */ |
| ClassDeclarations aclasses; |
| for (size_t i = 0; i < decl->members->length; i++) |
| { |
| Dsymbol *member = (*decl->members)[i]; |
| member->addLocalClass (&aclasses); |
| } |
| |
| if (aclasses.length) |
| { |
| layout_moduleinfo_field (size_type_node, type, offset); |
| layout_moduleinfo_field (make_array_type (Type::tvoidptr, |
| aclasses.length), |
| type, offset); |
| } |
| |
| /* Lastly, the name of the module is a static char array. */ |
| size_t namelen = strlen (decl->toPrettyChars ()) + 1; |
| layout_moduleinfo_field (make_array_type (Type::tchar, namelen), |
| type, offset); |
| |
| size_t alignsize = MAX (TYPE_ALIGN_UNIT (type), |
| TYPE_ALIGN_UNIT (ptr_type_node)); |
| finish_aggregate_type (offset, alignsize, type); |
| |
| return type; |
| } |
| |
| /* Output the ModuleInfo for module DECL and register it with druntime. */ |
| |
| static void |
| layout_moduleinfo (Module *decl) |
| { |
| ClassDeclarations aclasses; |
| FuncDeclaration *sgetmembers; |
| |
| for (size_t i = 0; i < decl->members->length; i++) |
| { |
| Dsymbol *member = (*decl->members)[i]; |
| member->addLocalClass (&aclasses); |
| } |
| |
| size_t aimports_dim = decl->aimports.length; |
| for (size_t i = 0; i < decl->aimports.length; i++) |
| { |
| Module *mi = decl->aimports[i]; |
| if (!mi->needmoduleinfo) |
| aimports_dim--; |
| } |
| |
| sgetmembers = decl->findGetMembers (); |
| |
| size_t flags = 0; |
| if (decl->sctor) |
| flags |= MItlsctor; |
| if (decl->sdtor) |
| flags |= MItlsdtor; |
| if (decl->ssharedctor) |
| flags |= MIctor; |
| if (decl->sshareddtor) |
| flags |= MIdtor; |
| if (sgetmembers) |
| flags |= MIxgetMembers; |
| if (decl->sictor) |
| flags |= MIictor; |
| if (decl->stest) |
| flags |= MIunitTest; |
| if (aimports_dim) |
| flags |= MIimportedModules; |
| if (aclasses.length) |
| flags |= MIlocalClasses; |
| if (!decl->needmoduleinfo) |
| flags |= MIstandalone; |
| |
| flags |= MIname; |
| |
| tree minfo = get_moduleinfo_decl (decl); |
| tree type = layout_moduleinfo_fields (decl, TREE_TYPE (minfo)); |
| |
| /* Put out the two named fields in a ModuleInfo decl: |
| uint flags; |
| uint index; */ |
| vec <constructor_elt, va_gc> *minit = NULL; |
| |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, |
| build_integer_cst (flags, d_uint_type)); |
| |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, |
| build_integer_cst (0, d_uint_type)); |
| |
| /* Order of appearance, depending on flags: |
| void function() tlsctor; |
| void function() tlsdtor; |
| void* function() xgetMembers; |
| void function() ctor; |
| void function() dtor; |
| void function() ictor; |
| void function() unitTest; |
| ModuleInfo*[] importedModules; |
| TypeInfo_Class[] localClasses; |
| char[N] name; |
| */ |
| if (flags & MItlsctor) |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sctor)); |
| |
| if (flags & MItlsdtor) |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sdtor)); |
| |
| if (flags & MIctor) |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, |
| build_address (decl->ssharedctor)); |
| |
| if (flags & MIdtor) |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, |
| build_address (decl->sshareddtor)); |
| |
| if (flags & MIxgetMembers) |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, |
| build_address (get_symbol_decl (sgetmembers))); |
| |
| if (flags & MIictor) |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sictor)); |
| |
| if (flags & MIunitTest) |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->stest)); |
| |
| if (flags & MIimportedModules) |
| { |
| vec <constructor_elt, va_gc> *elms = NULL; |
| tree satype = make_array_type (Type::tvoidptr, aimports_dim); |
| size_t idx = 0; |
| |
| for (size_t i = 0; i < decl->aimports.length; i++) |
| { |
| Module *mi = decl->aimports[i]; |
| if (mi->needmoduleinfo) |
| { |
| CONSTRUCTOR_APPEND_ELT (elms, size_int (idx), |
| build_address (get_moduleinfo_decl (mi))); |
| idx++; |
| } |
| } |
| |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, size_int (aimports_dim)); |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, |
| build_constructor (satype, elms)); |
| } |
| |
| if (flags & MIlocalClasses) |
| { |
| vec <constructor_elt, va_gc> *elms = NULL; |
| tree satype = make_array_type (Type::tvoidptr, aclasses.length); |
| |
| for (size_t i = 0; i < aclasses.length; i++) |
| { |
| ClassDeclaration *cd = aclasses[i]; |
| CONSTRUCTOR_APPEND_ELT (elms, size_int (i), |
| build_address (get_classinfo_decl (cd))); |
| } |
| |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, size_int (aclasses.length)); |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, |
| build_constructor (satype, elms)); |
| } |
| |
| if (flags & MIname) |
| { |
| /* Put out module name as a 0-terminated C-string, to save bytes. */ |
| const char *name = decl->toPrettyChars (); |
| size_t namelen = strlen (name) + 1; |
| tree strtree = build_string (namelen, name); |
| TREE_TYPE (strtree) = make_array_type (Type::tchar, namelen); |
| CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, strtree); |
| } |
| |
| TREE_TYPE (minfo) = type; |
| DECL_INITIAL (minfo) = build_struct_literal (type, minit); |
| d_finish_decl (minfo); |
| |
| /* Register the module against druntime. */ |
| register_moduleinfo (decl, minfo); |
| } |
| |
| /* Send the Module AST class DECL to GCC back-end. */ |
| |
| void |
| build_module_tree (Module *decl) |
| { |
| /* There may be more than one module per object file, but should only |
| ever compile them one at a time. */ |
| assert (!current_moduleinfo && !current_module_decl); |
| |
| module_info mi = module_info (); |
| module_info mitest = module_info (); |
| |
| current_moduleinfo = &mi; |
| current_testing_module = &mitest; |
| current_module_decl = decl; |
| |
| /* Layout module members. */ |
| if (decl->members) |
| { |
| for (size_t i = 0; i < decl->members->length; i++) |
| { |
| Dsymbol *s = (*decl->members)[i]; |
| build_decl_tree (s); |
| } |
| } |
| |
| /* For libphobos-internal use only. Generate a separate module info symbol |
| that references all compiled in unittests, this allows compiling library |
| modules and linking to libphobos without having run-time conflicts because |
| of two ModuleInfo records with the same name being present in two DSOs. */ |
| if (flag_building_libphobos_tests) |
| { |
| /* Associate the module info symbol with a mock module. */ |
| const char *name = concat (GDC_PREFIX ("modtest__"), |
| decl->ident->toChars (), NULL); |
| Module *tm = Module::create (decl->arg, Identifier::idPool (name), 0, 0); |
| Dsymbols members; |
| |
| /* Setting parent puts module in the same package as the current, to |
| avoid any symbol conflicts. */ |
| tm->parent = decl->parent; |
| tm->needmoduleinfo = decl->needmoduleinfo; |
| tm->members = &members; |
| /* Register the current module as being imported by the mock module. |
| This informs run-time that there is a dependency between the two. */ |
| tm->aimports.push (decl); |
| |
| if (mitest.ctors || mitest.ctorgates) |
| tm->sctor = build_funcs_gates_fn (get_identifier ("*__modtestctor"), |
| mitest.ctors, mitest.ctorgates); |
| |
| if (mitest.dtors) |
| tm->sdtor = build_funcs_gates_fn (get_identifier ("*__modtestdtor"), |
| mitest.dtors, NULL); |
| |
| if (mitest.sharedctors || mitest.sharedctorgates) |
| tm->ssharedctor |
| = build_funcs_gates_fn (get_identifier ("*__modtestsharedctor"), |
| mitest.sharedctors, mitest.sharedctorgates); |
| |
| if (mitest.shareddtors) |
| tm->sshareddtor |
| = build_funcs_gates_fn (get_identifier ("*__modtestshareddtor"), |
| mitest.shareddtors, NULL); |
| |
| if (mi.unitTests) |
| tm->stest = build_funcs_gates_fn (get_identifier ("*__modtest"), |
| mi.unitTests, NULL); |
| |
| mi.unitTests = NULL; |
| layout_moduleinfo (tm); |
| } |
| |
| /* Default behavior is to always generate module info because of templates. |
| Can be switched off for not compiling against runtime library. */ |
| if (global.params.useModuleInfo |
| && Module::moduleinfo != NULL |
| && decl->ident != Identifier::idPool ("__entrypoint")) |
| { |
| if (mi.ctors || mi.ctorgates) |
| decl->sctor = build_funcs_gates_fn (get_identifier ("*__modctor"), |
| mi.ctors, mi.ctorgates); |
| |
| if (mi.dtors) |
| decl->sdtor = build_funcs_gates_fn (get_identifier ("*__moddtor"), |
| mi.dtors, NULL); |
| |
| if (mi.sharedctors || mi.sharedctorgates) |
| decl->ssharedctor |
| = build_funcs_gates_fn (get_identifier ("*__modsharedctor"), |
| mi.sharedctors, mi.sharedctorgates); |
| |
| if (mi.shareddtors) |
| decl->sshareddtor |
| = build_funcs_gates_fn (get_identifier ("*__modshareddtor"), |
| mi.shareddtors, NULL); |
| |
| if (mi.unitTests) |
| decl->stest = build_funcs_gates_fn (get_identifier ("*__modtest"), |
| mi.unitTests, NULL); |
| |
| layout_moduleinfo (decl); |
| } |
| |
| current_moduleinfo = NULL; |
| current_testing_module = NULL; |
| current_module_decl = NULL; |
| } |
| |
| /* Returns the current function or module context for the purpose |
| of imported_module_or_decl. */ |
| |
| tree |
| d_module_context (void) |
| { |
| if (cfun != NULL) |
| return current_function_decl; |
| |
| gcc_assert (current_module_decl != NULL); |
| return build_import_decl (current_module_decl); |
| } |
| |
| /* Maybe record declaration D against our module information structure. */ |
| |
| void |
| register_module_decl (Declaration *d) |
| { |
| FuncDeclaration *fd = d->isFuncDeclaration (); |
| if (fd != NULL) |
| { |
| tree decl = get_symbol_decl (fd); |
| |
| /* Any module constructors or destructors that are only present when |
| compiling in unittests are kept track of separately so they are |
| not omitted when compiling with -fbuilding-libphobos-tests. */ |
| module_info *minfo; |
| if (flag_building_libphobos_tests && !fd->isUnitTestDeclaration () |
| && DECL_IN_UNITTEST_CONDITION_P (decl)) |
| minfo = current_testing_module; |
| else |
| minfo = current_moduleinfo; |
| |
| gcc_assert (minfo != NULL); |
| |
| /* If a static constructor, push into the current ModuleInfo. |
| Checks for `shared' first because it derives from the non-shared |
| constructor type in the front-end. */ |
| if (fd->isSharedStaticCtorDeclaration ()) |
| vec_safe_push (minfo->sharedctors, decl); |
| else if (fd->isStaticCtorDeclaration ()) |
| vec_safe_push (minfo->ctors, decl); |
| |
| /* If a static destructor, do same as with constructors, but also |
| increment the destructor's vgate at construction time. */ |
| if (fd->isSharedStaticDtorDeclaration ()) |
| { |
| VarDeclaration *vgate = ((SharedStaticDtorDeclaration *) fd)->vgate; |
| if (vgate != NULL) |
| { |
| tree gate = get_symbol_decl (vgate); |
| vec_safe_push (minfo->sharedctorgates, gate); |
| } |
| vec_safe_insert (minfo->shareddtors, 0, decl); |
| } |
| else if (fd->isStaticDtorDeclaration ()) |
| { |
| VarDeclaration *vgate = ((StaticDtorDeclaration *) fd)->vgate; |
| if (vgate != NULL) |
| { |
| tree gate = get_symbol_decl (vgate); |
| vec_safe_push (minfo->ctorgates, gate); |
| } |
| vec_safe_insert (minfo->dtors, 0, decl); |
| } |
| |
| /* If a unittest function. */ |
| if (fd->isUnitTestDeclaration ()) |
| vec_safe_push (minfo->unitTests, decl); |
| } |
| } |
| |
| /* Wrapup all global declarations and start the final compilation. */ |
| |
| void |
| d_finish_compilation (tree *vec, int len) |
| { |
| /* Complete all generated thunks. */ |
| symtab->process_same_body_aliases (); |
| |
| /* Process all file scopes in this compilation, and the external_scope, |
| through wrapup_global_declarations. */ |
| for (int i = 0; i < len; i++) |
| { |
| tree decl = vec[i]; |
| wrapup_global_declarations (&decl, 1); |
| } |
| } |