mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-22 23:24:59 +00:00
LinkModules.cpp: don't repeat names in comments.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@220662 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -36,47 +36,44 @@ using namespace llvm;
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
typedef SmallPtrSet<StructType*, 32> TypeSet;
|
typedef SmallPtrSet<StructType *, 32> TypeSet;
|
||||||
|
|
||||||
class TypeMapTy : public ValueMapTypeRemapper {
|
class TypeMapTy : public ValueMapTypeRemapper {
|
||||||
/// MappedTypes - This is a mapping from a source type to a destination type
|
/// This is a mapping from a source type to a destination type to use.
|
||||||
/// to use.
|
|
||||||
DenseMap<Type*, Type*> MappedTypes;
|
DenseMap<Type*, Type*> MappedTypes;
|
||||||
|
|
||||||
/// SpeculativeTypes - When checking to see if two subgraphs are isomorphic,
|
/// When checking to see if two subgraphs are isomorphic, we speculatively
|
||||||
/// we speculatively add types to MappedTypes, but keep track of them here in
|
/// add types to MappedTypes, but keep track of them here in case we need to
|
||||||
/// case we need to roll back.
|
/// roll back.
|
||||||
SmallVector<Type*, 16> SpeculativeTypes;
|
SmallVector<Type*, 16> SpeculativeTypes;
|
||||||
|
|
||||||
/// SrcDefinitionsToResolve - This is a list of non-opaque structs in the
|
/// This is a list of non-opaque structs in the source module that are mapped
|
||||||
/// source module that are mapped to an opaque struct in the destination
|
/// to an opaque struct in the destination module.
|
||||||
/// module.
|
|
||||||
SmallVector<StructType*, 16> SrcDefinitionsToResolve;
|
SmallVector<StructType*, 16> SrcDefinitionsToResolve;
|
||||||
|
|
||||||
/// DstResolvedOpaqueTypes - This is the set of opaque types in the
|
/// This is the set of opaque types in the destination modules who are
|
||||||
/// destination modules who are getting a body from the source module.
|
/// getting a body from the source module.
|
||||||
SmallPtrSet<StructType*, 16> DstResolvedOpaqueTypes;
|
SmallPtrSet<StructType*, 16> DstResolvedOpaqueTypes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TypeMapTy(TypeSet &Set) : DstStructTypesSet(Set) {}
|
TypeMapTy(TypeSet &Set) : DstStructTypesSet(Set) {}
|
||||||
|
|
||||||
TypeSet &DstStructTypesSet;
|
TypeSet &DstStructTypesSet;
|
||||||
/// addTypeMapping - Indicate that the specified type in the destination
|
/// Indicate that the specified type in the destination module is conceptually
|
||||||
/// module is conceptually equivalent to the specified type in the source
|
/// equivalent to the specified type in the source module.
|
||||||
/// module.
|
|
||||||
void addTypeMapping(Type *DstTy, Type *SrcTy);
|
void addTypeMapping(Type *DstTy, Type *SrcTy);
|
||||||
|
|
||||||
/// linkDefinedTypeBodies - Produce a body for an opaque type in the dest
|
/// linkDefinedTypeBodies - Produce a body for an opaque type in the dest
|
||||||
/// module from a type definition in the source module.
|
/// module from a type definition in the source module.
|
||||||
void linkDefinedTypeBodies();
|
void linkDefinedTypeBodies();
|
||||||
|
|
||||||
/// get - Return the mapped type to use for the specified input type from the
|
/// Return the mapped type to use for the specified input type from the
|
||||||
/// source module.
|
/// source module.
|
||||||
Type *get(Type *SrcTy);
|
Type *get(Type *SrcTy);
|
||||||
|
|
||||||
FunctionType *get(FunctionType *T) {return cast<FunctionType>(get((Type*)T));}
|
FunctionType *get(FunctionType *T) {return cast<FunctionType>(get((Type*)T));}
|
||||||
|
|
||||||
/// dump - Dump out the type map for debugging purposes.
|
/// Dump out the type map for debugging purposes.
|
||||||
void dump() const {
|
void dump() const {
|
||||||
for (DenseMap<Type*, Type*>::const_iterator
|
for (DenseMap<Type*, Type*>::const_iterator
|
||||||
I = MappedTypes.begin(), E = MappedTypes.end(); I != E; ++I) {
|
I = MappedTypes.begin(), E = MappedTypes.end(); I != E; ++I) {
|
||||||
@@ -90,7 +87,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Type *getImpl(Type *T);
|
Type *getImpl(Type *T);
|
||||||
/// remapType - Implement the ValueMapTypeRemapper interface.
|
/// Implement the ValueMapTypeRemapper interface.
|
||||||
Type *remapType(Type *SrcTy) override {
|
Type *remapType(Type *SrcTy) override {
|
||||||
return get(SrcTy);
|
return get(SrcTy);
|
||||||
}
|
}
|
||||||
@@ -119,8 +116,8 @@ void TypeMapTy::addTypeMapping(Type *DstTy, Type *SrcTy) {
|
|||||||
SpeculativeTypes.clear();
|
SpeculativeTypes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// areTypesIsomorphic - Recursively walk this pair of types, returning true
|
/// Recursively walk this pair of types, returning true if they are isomorphic,
|
||||||
/// if they are isomorphic, false if they are not.
|
/// false if they are not.
|
||||||
bool TypeMapTy::areTypesIsomorphic(Type *DstTy, Type *SrcTy) {
|
bool TypeMapTy::areTypesIsomorphic(Type *DstTy, Type *SrcTy) {
|
||||||
// Two types with differing kinds are clearly not isomorphic.
|
// Two types with differing kinds are clearly not isomorphic.
|
||||||
if (DstTy->getTypeID() != SrcTy->getTypeID()) return false;
|
if (DstTy->getTypeID() != SrcTy->getTypeID()) return false;
|
||||||
@@ -204,8 +201,8 @@ bool TypeMapTy::areTypesIsomorphic(Type *DstTy, Type *SrcTy) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// linkDefinedTypeBodies - Produce a body for an opaque type in the dest
|
/// Produce a body for an opaque type in the dest module from a type definition
|
||||||
/// module from a type definition in the source module.
|
/// in the source module.
|
||||||
void TypeMapTy::linkDefinedTypeBodies() {
|
void TypeMapTy::linkDefinedTypeBodies() {
|
||||||
SmallVector<Type*, 16> Elements;
|
SmallVector<Type*, 16> Elements;
|
||||||
SmallString<16> TmpName;
|
SmallString<16> TmpName;
|
||||||
@@ -245,8 +242,6 @@ void TypeMapTy::linkDefinedTypeBodies() {
|
|||||||
DstResolvedOpaqueTypes.clear();
|
DstResolvedOpaqueTypes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get - Return the mapped type to use for the specified input type from the
|
|
||||||
/// source module.
|
|
||||||
Type *TypeMapTy::get(Type *Ty) {
|
Type *TypeMapTy::get(Type *Ty) {
|
||||||
Type *Result = getImpl(Ty);
|
Type *Result = getImpl(Ty);
|
||||||
|
|
||||||
@@ -256,7 +251,7 @@ Type *TypeMapTy::get(Type *Ty) {
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getImpl - This is the recursive version of get().
|
/// This is the recursive version of get().
|
||||||
Type *TypeMapTy::getImpl(Type *Ty) {
|
Type *TypeMapTy::getImpl(Type *Ty) {
|
||||||
// If we already have an entry for this type, return it.
|
// If we already have an entry for this type, return it.
|
||||||
Type **Entry = &MappedTypes[Ty];
|
Type **Entry = &MappedTypes[Ty];
|
||||||
@@ -362,9 +357,9 @@ Type *TypeMapTy::getImpl(Type *Ty) {
|
|||||||
namespace {
|
namespace {
|
||||||
class ModuleLinker;
|
class ModuleLinker;
|
||||||
|
|
||||||
/// ValueMaterializerTy - Creates prototypes for functions that are lazily
|
/// Creates prototypes for functions that are lazily linked on the fly. This
|
||||||
/// linked on the fly. This speeds up linking for modules with many
|
/// speeds up linking for modules with many/ lazily linked functions of which
|
||||||
/// lazily linked functions of which few get used.
|
/// few get used.
|
||||||
class ValueMaterializerTy : public ValueMaterializer {
|
class ValueMaterializerTy : public ValueMaterializer {
|
||||||
TypeMapTy &TypeMap;
|
TypeMapTy &TypeMap;
|
||||||
Module *DstM;
|
Module *DstM;
|
||||||
@@ -393,18 +388,18 @@ namespace {
|
|||||||
void LinkDiagnosticInfo::print(DiagnosticPrinter &DP) const { DP << Msg; }
|
void LinkDiagnosticInfo::print(DiagnosticPrinter &DP) const { DP << Msg; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ModuleLinker - This is an implementation class for the LinkModules
|
/// This is an implementation class for the LinkModules function, which is the
|
||||||
/// function, which is the entrypoint for this file.
|
/// entrypoint for this file.
|
||||||
class ModuleLinker {
|
class ModuleLinker {
|
||||||
Module *DstM, *SrcM;
|
Module *DstM, *SrcM;
|
||||||
|
|
||||||
TypeMapTy TypeMap;
|
TypeMapTy TypeMap;
|
||||||
ValueMaterializerTy ValMaterializer;
|
ValueMaterializerTy ValMaterializer;
|
||||||
|
|
||||||
/// ValueMap - Mapping of values from what they used to be in Src, to what
|
/// Mapping of values from what they used to be in Src, to what they are now
|
||||||
/// they are now in DstM. ValueToValueMapTy is a ValueMap, which involves
|
/// in DstM. ValueToValueMapTy is a ValueMap, which involves some overhead
|
||||||
/// some overhead due to the use of Value handles which the Linker doesn't
|
/// due to the use of Value handles which the Linker doesn't actually need,
|
||||||
/// actually need, but this allows us to reuse the ValueMapper code.
|
/// but this allows us to reuse the ValueMapper code.
|
||||||
ValueToValueMapTy ValueMap;
|
ValueToValueMapTy ValueMap;
|
||||||
|
|
||||||
struct AppendingVarInfo {
|
struct AppendingVarInfo {
|
||||||
@@ -456,15 +451,15 @@ namespace {
|
|||||||
bool getComdatResult(const Comdat *SrcC, Comdat::SelectionKind &SK,
|
bool getComdatResult(const Comdat *SrcC, Comdat::SelectionKind &SK,
|
||||||
bool &LinkFromSrc);
|
bool &LinkFromSrc);
|
||||||
|
|
||||||
/// getLinkageResult - This analyzes the two global values and determines
|
/// This analyzes the two global values and determines what the result will
|
||||||
/// what the result will look like in the destination module.
|
/// look like in the destination module.
|
||||||
bool getLinkageResult(GlobalValue *Dest, const GlobalValue *Src,
|
bool getLinkageResult(GlobalValue *Dest, const GlobalValue *Src,
|
||||||
GlobalValue::LinkageTypes <,
|
GlobalValue::LinkageTypes <,
|
||||||
GlobalValue::VisibilityTypes &Vis,
|
GlobalValue::VisibilityTypes &Vis,
|
||||||
bool &LinkFromSrc);
|
bool &LinkFromSrc);
|
||||||
|
|
||||||
/// getLinkedToGlobal - Given a global in the source module, return the
|
/// Given a global in the source module, return the global in the
|
||||||
/// global in the destination module that is being linked to, if any.
|
/// destination module that is being linked to, if any.
|
||||||
GlobalValue *getLinkedToGlobal(GlobalValue *SrcGV) {
|
GlobalValue *getLinkedToGlobal(GlobalValue *SrcGV) {
|
||||||
// If the source has no name it can't link. If it has local linkage,
|
// If the source has no name it can't link. If it has local linkage,
|
||||||
// there is no name match-up going on.
|
// there is no name match-up going on.
|
||||||
@@ -503,9 +498,9 @@ namespace {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// forceRenaming - The LLVM SymbolTable class autorenames globals that conflict
|
/// The LLVM SymbolTable class autorenames globals that conflict in the symbol
|
||||||
/// in the symbol table. This is good for all clients except for us. Go
|
/// table. This is good for all clients except for us. Go through the trouble
|
||||||
/// through the trouble to force this back.
|
/// to force this back.
|
||||||
static void forceRenaming(GlobalValue *GV, StringRef Name) {
|
static void forceRenaming(GlobalValue *GV, StringRef Name) {
|
||||||
// If the global doesn't force its name or if it already has the right name,
|
// If the global doesn't force its name or if it already has the right name,
|
||||||
// there is nothing for us to do.
|
// there is nothing for us to do.
|
||||||
@@ -524,8 +519,8 @@ static void forceRenaming(GlobalValue *GV, StringRef Name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// copyGVAttributes - copy additional attributes (those not needed to construct
|
/// copy additional attributes (those not needed to construct a GlobalValue)
|
||||||
/// a GlobalValue) from the SrcGV to the DestGV.
|
/// from the SrcGV to the DestGV.
|
||||||
static void copyGVAttributes(GlobalValue *DestGV, const GlobalValue *SrcGV) {
|
static void copyGVAttributes(GlobalValue *DestGV, const GlobalValue *SrcGV) {
|
||||||
// Use the maximum alignment, rather than just copying the alignment of SrcGV.
|
// Use the maximum alignment, rather than just copying the alignment of SrcGV.
|
||||||
auto *DestGO = dyn_cast<GlobalObject>(DestGV);
|
auto *DestGO = dyn_cast<GlobalObject>(DestGV);
|
||||||
@@ -789,10 +784,10 @@ bool ModuleLinker::getLinkageResult(GlobalValue *Dest, const GlobalValue *Src,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// computeTypeMapping - Loop over all of the linked values to compute type
|
/// Loop over all of the linked values to compute type mappings. For example,
|
||||||
/// mappings. For example, if we link "extern Foo *x" and "Foo *x = NULL", then
|
/// if we link "extern Foo *x" and "Foo *x = NULL", then we have two struct
|
||||||
/// we have two struct types 'Foo' but one got renamed when the module was
|
/// types 'Foo' but one got renamed when the module was loaded into the same
|
||||||
/// loaded into the same LLVMContext.
|
/// LLVMContext.
|
||||||
void ModuleLinker::computeTypeMapping() {
|
void ModuleLinker::computeTypeMapping() {
|
||||||
// Incorporate globals.
|
// Incorporate globals.
|
||||||
for (Module::global_iterator I = SrcM->global_begin(),
|
for (Module::global_iterator I = SrcM->global_begin(),
|
||||||
@@ -944,8 +939,8 @@ void ModuleLinker::upgradeMismatchedGlobals() {
|
|||||||
upgradeMismatchedGlobalArray("llvm.global_dtors");
|
upgradeMismatchedGlobalArray("llvm.global_dtors");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// linkAppendingVarProto - If there were any appending global variables, link
|
/// If there were any appending global variables, link them together now.
|
||||||
/// them together now. Return true on error.
|
/// Return true on error.
|
||||||
bool ModuleLinker::linkAppendingVarProto(GlobalVariable *DstGV,
|
bool ModuleLinker::linkAppendingVarProto(GlobalVariable *DstGV,
|
||||||
GlobalVariable *SrcGV) {
|
GlobalVariable *SrcGV) {
|
||||||
|
|
||||||
@@ -1012,8 +1007,8 @@ bool ModuleLinker::linkAppendingVarProto(GlobalVariable *DstGV,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// linkGlobalProto - Loop through the global variables in the src module and
|
/// Loop through the global variables in the src module and merge them into the
|
||||||
/// merge them into the dest module.
|
/// dest module.
|
||||||
bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
|
bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
|
||||||
GlobalValue *DGV = getLinkedToGlobal(SGV);
|
GlobalValue *DGV = getLinkedToGlobal(SGV);
|
||||||
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
|
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
|
||||||
@@ -1114,8 +1109,8 @@ bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// linkFunctionProto - Link the function in the source module into the
|
/// Link the function in the source module into the destination module if
|
||||||
/// destination module if needed, setting up mapping information.
|
/// needed, setting up mapping information.
|
||||||
bool ModuleLinker::linkFunctionProto(Function *SF) {
|
bool ModuleLinker::linkFunctionProto(Function *SF) {
|
||||||
GlobalValue *DGV = getLinkedToGlobal(SF);
|
GlobalValue *DGV = getLinkedToGlobal(SF);
|
||||||
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
|
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
|
||||||
@@ -1195,8 +1190,7 @@ bool ModuleLinker::linkFunctionProto(Function *SF) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// LinkAliasProto - Set up prototypes for any aliases that come over from the
|
/// Set up prototypes for any aliases that come over from the source module.
|
||||||
/// source module.
|
|
||||||
bool ModuleLinker::linkAliasProto(GlobalAlias *SGA) {
|
bool ModuleLinker::linkAliasProto(GlobalAlias *SGA) {
|
||||||
GlobalValue *DGV = getLinkedToGlobal(SGA);
|
GlobalValue *DGV = getLinkedToGlobal(SGA);
|
||||||
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
|
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
|
||||||
@@ -1305,8 +1299,8 @@ void ModuleLinker::linkAppendingVarInit(const AppendingVarInfo &AVI) {
|
|||||||
AVI.NewGV->setInitializer(ConstantArray::get(NewType, DstElements));
|
AVI.NewGV->setInitializer(ConstantArray::get(NewType, DstElements));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// linkGlobalInits - Update the initializers in the Dest module now that all
|
/// Update the initializers in the Dest module now that all globals that may be
|
||||||
/// globals that may be referenced are in Dest.
|
/// referenced are in Dest.
|
||||||
void ModuleLinker::linkGlobalInits() {
|
void ModuleLinker::linkGlobalInits() {
|
||||||
// Loop over all of the globals in the src module, mapping them over as we go
|
// Loop over all of the globals in the src module, mapping them over as we go
|
||||||
for (Module::const_global_iterator I = SrcM->global_begin(),
|
for (Module::const_global_iterator I = SrcM->global_begin(),
|
||||||
@@ -1323,9 +1317,9 @@ void ModuleLinker::linkGlobalInits() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// linkFunctionBody - Copy the source function over into the dest function and
|
/// Copy the source function over into the dest function and fix up references
|
||||||
/// fix up references to values. At this point we know that Dest is an external
|
/// to values. At this point we know that Dest is an external function, and
|
||||||
/// function, and that Src is not.
|
/// that Src is not.
|
||||||
void ModuleLinker::linkFunctionBody(Function *Dst, Function *Src) {
|
void ModuleLinker::linkFunctionBody(Function *Dst, Function *Src) {
|
||||||
assert(Src && Dst && Dst->isDeclaration() && !Src->isDeclaration());
|
assert(Src && Dst && Dst->isDeclaration() && !Src->isDeclaration());
|
||||||
|
|
||||||
@@ -1366,7 +1360,7 @@ void ModuleLinker::linkFunctionBody(Function *Dst, Function *Src) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// linkAliasBodies - Insert all of the aliases in Src into the Dest module.
|
/// Insert all of the aliases in Src into the Dest module.
|
||||||
void ModuleLinker::linkAliasBodies() {
|
void ModuleLinker::linkAliasBodies() {
|
||||||
for (Module::alias_iterator I = SrcM->alias_begin(), E = SrcM->alias_end();
|
for (Module::alias_iterator I = SrcM->alias_begin(), E = SrcM->alias_end();
|
||||||
I != E; ++I) {
|
I != E; ++I) {
|
||||||
@@ -1381,8 +1375,7 @@ void ModuleLinker::linkAliasBodies() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// linkNamedMDNodes - Insert all of the named MDNodes in Src into the Dest
|
/// Insert all of the named MDNodes in Src into the Dest module.
|
||||||
/// module.
|
|
||||||
void ModuleLinker::linkNamedMDNodes() {
|
void ModuleLinker::linkNamedMDNodes() {
|
||||||
const NamedMDNode *SrcModFlags = SrcM->getModuleFlagsMetadata();
|
const NamedMDNode *SrcModFlags = SrcM->getModuleFlagsMetadata();
|
||||||
for (Module::const_named_metadata_iterator I = SrcM->named_metadata_begin(),
|
for (Module::const_named_metadata_iterator I = SrcM->named_metadata_begin(),
|
||||||
@@ -1397,8 +1390,7 @@ void ModuleLinker::linkNamedMDNodes() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// linkModuleFlagsMetadata - Merge the linker flags in Src into the Dest
|
/// Merge the linker flags in Src into the Dest module.
|
||||||
/// module.
|
|
||||||
bool ModuleLinker::linkModuleFlagsMetadata() {
|
bool ModuleLinker::linkModuleFlagsMetadata() {
|
||||||
// If the source module has no module flags, we are done.
|
// If the source module has no module flags, we are done.
|
||||||
const NamedMDNode *SrcModFlags = SrcM->getModuleFlagsMetadata();
|
const NamedMDNode *SrcModFlags = SrcM->getModuleFlagsMetadata();
|
||||||
@@ -1752,11 +1744,11 @@ bool Linker::linkInModule(Module *Src, unsigned Mode) {
|
|||||||
// LinkModules entrypoint.
|
// LinkModules entrypoint.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// LinkModules - This function links two modules together, with the resulting
|
/// This function links two modules together, with the resulting Dest module
|
||||||
/// Dest module modified to be the composite of the two input modules. If an
|
/// modified to be the composite of the two input modules. If an error occurs,
|
||||||
/// error occurs, true is returned and ErrorMsg (if not null) is set to indicate
|
/// true is returned and ErrorMsg (if not null) is set to indicate the problem.
|
||||||
/// the problem. Upon failure, the Dest module could be in a modified state,
|
/// Upon failure, the Dest module could be in a modified state, and shouldn't be
|
||||||
/// and shouldn't be relied on to be consistent.
|
/// relied on to be consistent.
|
||||||
bool Linker::LinkModules(Module *Dest, Module *Src, unsigned Mode) {
|
bool Linker::LinkModules(Module *Dest, Module *Src, unsigned Mode) {
|
||||||
Linker L(Dest);
|
Linker L(Dest);
|
||||||
return L.linkInModule(Src, Mode);
|
return L.linkInModule(Src, Mode);
|
||||||
|
Reference in New Issue
Block a user