mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[sil-linker] Improve the implementation of the hasSILFunction API
It it now possible to check if a function with a given name and a given linkage exists in one of the modules, even if the current module contains a function with this name but a difference linkage. This is useful e.g. for performing a lookup of pre-specializations.
This commit is contained in:
@@ -94,6 +94,7 @@ public:
|
|||||||
SILFunction *
|
SILFunction *
|
||||||
lookupSILFunction(StringRef Name, bool declarationOnly = false,
|
lookupSILFunction(StringRef Name, bool declarationOnly = false,
|
||||||
SILLinkage linkage = SILLinkage::Private);
|
SILLinkage linkage = SILLinkage::Private);
|
||||||
|
bool hasSILFunction(StringRef Name, SILLinkage linkage = SILLinkage::Private);
|
||||||
SILVTable *lookupVTable(Identifier Name);
|
SILVTable *lookupVTable(Identifier Name);
|
||||||
SILVTable *lookupVTable(const ClassDecl *C) {
|
SILVTable *lookupVTable(const ClassDecl *C) {
|
||||||
return lookupVTable(C->getName());
|
return lookupVTable(C->getName());
|
||||||
|
|||||||
@@ -139,6 +139,10 @@ SILFunction *SILLinkerVisitor::lookupFunction(StringRef Name,
|
|||||||
return NewFn;
|
return NewFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Process Decl, recursively deserializing any thing Decl may reference.
|
||||||
|
bool SILLinkerVisitor::hasFunction(StringRef Name, SILLinkage Linkage) {
|
||||||
|
return Loader->hasSILFunction(Name, Linkage);
|
||||||
|
}
|
||||||
|
|
||||||
/// Deserialize the VTable mapped to C if it exists and all SIL the VTable
|
/// Deserialize the VTable mapped to C if it exists and all SIL the VTable
|
||||||
/// transitively references.
|
/// transitively references.
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ public:
|
|||||||
/// this Name.
|
/// this Name.
|
||||||
SILFunction *lookupFunction(StringRef Name, SILLinkage Linkage);
|
SILFunction *lookupFunction(StringRef Name, SILLinkage Linkage);
|
||||||
|
|
||||||
|
/// Process Name, try to check if there is a declaration of a function
|
||||||
|
/// with this Name.
|
||||||
|
bool hasFunction(StringRef Name, SILLinkage Linkage);
|
||||||
|
|
||||||
/// Process Decl, recursively deserializing any thing that
|
/// Process Decl, recursively deserializing any thing that
|
||||||
/// the SILFunction corresponding to Decl may reference.
|
/// the SILFunction corresponding to Decl may reference.
|
||||||
bool processDeclRef(SILDeclRef Decl);
|
bool processDeclRef(SILDeclRef Decl);
|
||||||
|
|||||||
@@ -484,12 +484,48 @@ bool SILModule::linkFunction(StringRef Name, SILModule::LinkingMode Mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SILFunction *SILModule::hasFunction(StringRef Name, SILLinkage Linkage) {
|
SILFunction *SILModule::hasFunction(StringRef Name, SILLinkage Linkage) {
|
||||||
assert(!lookUpFunction(Name) && "hasFunction should be only called for "
|
SILFunction *F = lookUpFunction(Name);
|
||||||
"functions that are not contained in the "
|
|
||||||
"SILModule yet");
|
assert((Linkage == SILLinkage::Public ||
|
||||||
return SILLinkerVisitor(*this, getSILLoader(),
|
Linkage == SILLinkage::PublicExternal) &&
|
||||||
SILModule::LinkingMode::LinkNormal)
|
"Only a lookup of public functions is supported currently");
|
||||||
.lookupFunction(Name, Linkage);
|
|
||||||
|
// Nothing to do if the current module has a required function
|
||||||
|
// with a proper linkage.
|
||||||
|
if (F && F->getLinkage() == Linkage)
|
||||||
|
return F;
|
||||||
|
|
||||||
|
assert((!F || F->getLinkage() != Linkage) &&
|
||||||
|
"hasFunction should be only called for functions that are not "
|
||||||
|
"contained in the SILModule yet or do not have a required linkage");
|
||||||
|
(void)F;
|
||||||
|
|
||||||
|
SILLinkerVisitor Visitor(*this, getSILLoader(),
|
||||||
|
SILModule::LinkingMode::LinkNormal);
|
||||||
|
|
||||||
|
if (Visitor.hasFunction(Name, Linkage)) {
|
||||||
|
if (!F) {
|
||||||
|
// Load the function.
|
||||||
|
F = Visitor.lookupFunction(Name, Linkage);
|
||||||
|
assert(F && "Function should be present");
|
||||||
|
assert(F->getLinkage() == Linkage &&
|
||||||
|
"SILFunction has a wrong linkage");
|
||||||
|
}
|
||||||
|
// If a function exists already and it is a non-optimizing
|
||||||
|
// compilaiton, simply convert it into an external declaration,
|
||||||
|
// so that a compiled version from the shared library is used.
|
||||||
|
if (F->isDefinition() &&
|
||||||
|
F->getModule().getOptions().Optimization <
|
||||||
|
SILOptions::SILOptMode::Optimize) {
|
||||||
|
F->convertToDeclaration();
|
||||||
|
}
|
||||||
|
if (F->isExternalDeclaration())
|
||||||
|
F->setFragile(IsFragile_t::IsNotFragile);
|
||||||
|
F->setLinkage(Linkage);
|
||||||
|
} else {
|
||||||
|
F = nullptr;
|
||||||
|
}
|
||||||
|
return F;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SILModule::linkAllWitnessTables() {
|
void SILModule::linkAllWitnessTables() {
|
||||||
|
|||||||
@@ -1798,6 +1798,68 @@ SILFunction *SILDeserializer::lookupSILFunction(SILFunction *InFunc) {
|
|||||||
return Func;
|
return Func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check for existence of a function with a given name and required linkage.
|
||||||
|
/// This function is modelled after readSILFunction. But it does not
|
||||||
|
/// create a SILFunction object.
|
||||||
|
bool SILDeserializer::hasSILFunction(StringRef Name,
|
||||||
|
SILLinkage Linkage) {
|
||||||
|
if (!FuncTable)
|
||||||
|
return false;
|
||||||
|
auto iter = FuncTable->find(Name);
|
||||||
|
if (iter == FuncTable->end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// There is a function with the required name.
|
||||||
|
// Find out which linkage it has.
|
||||||
|
auto FID = *iter;
|
||||||
|
auto &cacheEntry = Funcs[FID-1];
|
||||||
|
if (cacheEntry.isFullyDeserialized() ||
|
||||||
|
(cacheEntry.isDeserialized()))
|
||||||
|
return cacheEntry.get()->getLinkage() == Linkage ||
|
||||||
|
Linkage == SILLinkage::Private;
|
||||||
|
|
||||||
|
BCOffsetRAII restoreOffset(SILCursor);
|
||||||
|
SILCursor.JumpToBit(cacheEntry.getOffset());
|
||||||
|
|
||||||
|
auto entry = SILCursor.advance(AF_DontPopBlockAtEnd);
|
||||||
|
if (entry.Kind == llvm::BitstreamEntry::Error) {
|
||||||
|
DEBUG(llvm::dbgs() << "Cursor advance error in hasSILFunction.\n");
|
||||||
|
MF->error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallVector<uint64_t, 64> scratch;
|
||||||
|
StringRef blobData;
|
||||||
|
unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData);
|
||||||
|
assert(kind == SIL_FUNCTION && "expect a sil function");
|
||||||
|
(void)kind;
|
||||||
|
|
||||||
|
// Read function properties only, e.g. its linkage and other attributes.
|
||||||
|
// TODO: If this results in any noticable performance problems, Cache the
|
||||||
|
// linkage to avoid re-reading it from the bitcode each time?
|
||||||
|
TypeID funcTyID;
|
||||||
|
unsigned rawLinkage, isTransparent, isFragile, isThunk, isGlobal,
|
||||||
|
inlineStrategy, effect, numSpecAttrs;
|
||||||
|
ArrayRef<uint64_t> SemanticsIDs;
|
||||||
|
SILFunctionLayout::readRecord(scratch, rawLinkage, isTransparent, isFragile,
|
||||||
|
isThunk, isGlobal, inlineStrategy, effect,
|
||||||
|
numSpecAttrs, funcTyID, SemanticsIDs);
|
||||||
|
auto linkage = fromStableSILLinkage(rawLinkage);
|
||||||
|
if (!linkage) {
|
||||||
|
DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage
|
||||||
|
<< " for SIL function " << Name << "\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bail if it is not a required linkage.
|
||||||
|
if (linkage.getValue() != Linkage && Linkage != SILLinkage::Private)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DEBUG(llvm::dbgs() << "Found SIL Function: " << Name << "\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SILFunction *SILDeserializer::lookupSILFunction(StringRef name,
|
SILFunction *SILDeserializer::lookupSILFunction(StringRef name,
|
||||||
bool declarationOnly) {
|
bool declarationOnly) {
|
||||||
if (!FuncTable)
|
if (!FuncTable)
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ public:
|
|||||||
SILFunction *lookupSILFunction(SILFunction *InFunc);
|
SILFunction *lookupSILFunction(SILFunction *InFunc);
|
||||||
SILFunction *lookupSILFunction(StringRef Name,
|
SILFunction *lookupSILFunction(StringRef Name,
|
||||||
bool declarationOnly = false);
|
bool declarationOnly = false);
|
||||||
|
bool hasSILFunction(StringRef Name, SILLinkage Linkage);
|
||||||
SILVTable *lookupVTable(Identifier Name);
|
SILVTable *lookupVTable(Identifier Name);
|
||||||
SILWitnessTable *lookupWitnessTable(SILWitnessTable *wt);
|
SILWitnessTable *lookupWitnessTable(SILWitnessTable *wt);
|
||||||
SILDefaultWitnessTable *
|
SILDefaultWitnessTable *
|
||||||
|
|||||||
@@ -104,6 +104,18 @@ SILFunction *SerializedSILLoader::lookupSILFunction(StringRef Name,
|
|||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SerializedSILLoader::hasSILFunction(StringRef Name, SILLinkage Linkage) {
|
||||||
|
// It is possible that one module has a declaration of a SILFunction, while
|
||||||
|
// another has the full definition.
|
||||||
|
SILFunction *retVal = nullptr;
|
||||||
|
for (auto &Des : LoadedSILSections) {
|
||||||
|
if (Des->hasSILFunction(Name, Linkage))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SILVTable *SerializedSILLoader::lookupVTable(Identifier Name) {
|
SILVTable *SerializedSILLoader::lookupVTable(Identifier Name) {
|
||||||
for (auto &Des : LoadedSILSections) {
|
for (auto &Des : LoadedSILSections) {
|
||||||
if (auto VT = Des->lookupVTable(Name))
|
if (auto VT = Des->lookupVTable(Name))
|
||||||
|
|||||||
Reference in New Issue
Block a user