935 lines
28 KiB
C++
935 lines
28 KiB
C++
/* 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 GTY(()) 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;
|
|
|
|
/* Static constructors and destructors (not D `static this'). */
|
|
|
|
static GTY(()) vec <tree, va_gc> *static_ctor_list;
|
|
static GTY(()) vec <tree, va_gc> *static_dtor_list;
|
|
|
|
/* Returns an internal function identified by IDENT. This is used
|
|
by both module initialization and dso handlers. */
|
|
|
|
static FuncDeclaration *
|
|
get_internal_fn (tree ident)
|
|
{
|
|
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->loc = Loc (mod->srcfile->toChars (), 1, 0);
|
|
fd->parent = mod;
|
|
fd->protection.kind = Prot::private_;
|
|
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);
|
|
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));
|
|
tree decl = get_symbol_decl (fd);
|
|
|
|
TREE_PUBLIC (decl) = 1;
|
|
DECL_ARTIFICIAL (decl) = 1;
|
|
DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
|
|
DECL_VISIBILITY_SPECIFIED (decl) = 1;
|
|
|
|
d_comdat_linkage (decl);
|
|
|
|
/* 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);
|
|
DECL_EXTERNAL (dso_slot_node) = 0;
|
|
d_comdat_linkage (dso_slot_node);
|
|
rest_of_decl_compilation (dso_slot_node, 1, 0);
|
|
|
|
dso_initialized_node = build_dso_registry_var (GDC_PREFIX ("dso_initialized"),
|
|
boolean_type_node);
|
|
DECL_EXTERNAL (dso_initialized_node) = 0;
|
|
d_comdat_linkage (dso_initialized_node);
|
|
rest_of_decl_compilation (dso_initialized_node, 1, 0);
|
|
|
|
/* Declare dso_ctor() and dso_dtor(). */
|
|
tree dso_ctor = build_dso_cdtor_fn (true);
|
|
vec_safe_push (static_ctor_list, dso_ctor);
|
|
|
|
tree dso_dtor = build_dso_cdtor_fn (false);
|
|
vec_safe_push (static_dtor_list, dso_dtor);
|
|
|
|
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);
|
|
}
|
|
|
|
/* If the target does not directly support static constructors,
|
|
static_ctor_list contains a list of all static constructors defined
|
|
so far. This routine will create a function to call all of those
|
|
and is picked up by collect2. */
|
|
if (static_ctor_list)
|
|
{
|
|
tree decl = build_funcs_gates_fn (get_file_function_name ("I"),
|
|
static_ctor_list, NULL);
|
|
DECL_STATIC_CONSTRUCTOR (decl) = 1;
|
|
decl_init_priority_insert (decl, DEFAULT_INIT_PRIORITY);
|
|
}
|
|
|
|
if (static_dtor_list)
|
|
{
|
|
tree decl = build_funcs_gates_fn (get_file_function_name ("D"),
|
|
static_dtor_list, NULL);
|
|
DECL_STATIC_DESTRUCTOR (decl) = 1;
|
|
decl_fini_priority_insert (decl, DEFAULT_INIT_PRIORITY);
|
|
}
|
|
}
|
|
|
|
|
|
#include "gt-d-modules.h"
|