diff options
author | Cyndy Ishida <cyndy_ishida@apple.com> | 2024-01-29 18:36:48 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-29 18:36:48 -0800 |
commit | 4460fa8814d4c86e1d22f830078d7bad69bc0ecc (patch) | |
tree | 5c72a118743042e8b55ec3f9eda9b2be244d3eef /llvm/lib/TextAPI | |
parent | 45188c64db68af92596acdb2d9022527f6aa4502 (diff) | |
download | llvm-4460fa8814d4c86e1d22f830078d7bad69bc0ecc.zip llvm-4460fa8814d4c86e1d22f830078d7bad69bc0ecc.tar.gz llvm-4460fa8814d4c86e1d22f830078d7bad69bc0ecc.tar.bz2 |
[TextAPI] Introduce granularity for handling ObjC Interface symbols (#79928)
ObjCInterfaceRecords roughly align to the objc-classes key in tbd-files.
They condensely represent up to 3 symbols. The problem here is that when
represented this way, we lose granularity when these symbols could have
different linkages or outright don't exist. This can happen frequently
in interoptable code generated by the swift compiler. This adds fields
and utility functions to express unique properties for these symbols. If
the record does represent the same properties across all of its symbols,
it will be treated the same in the TBD. Otherwise it will be printed in
global's section.
Reviewed seperately before by Juergen Ributzka
Diffstat (limited to 'llvm/lib/TextAPI')
-rw-r--r-- | llvm/lib/TextAPI/RecordVisitor.cpp | 37 | ||||
-rw-r--r-- | llvm/lib/TextAPI/RecordsSlice.cpp | 63 | ||||
-rw-r--r-- | llvm/lib/TextAPI/Symbol.cpp | 23 | ||||
-rw-r--r-- | llvm/lib/TextAPI/SymbolSet.cpp | 19 |
4 files changed, 106 insertions, 36 deletions
diff --git a/llvm/lib/TextAPI/RecordVisitor.cpp b/llvm/lib/TextAPI/RecordVisitor.cpp index b049c9e..3ff6bbd 100644 --- a/llvm/lib/TextAPI/RecordVisitor.cpp +++ b/llvm/lib/TextAPI/RecordVisitor.cpp @@ -28,10 +28,20 @@ static bool shouldSkipRecord(const Record &R, const bool RecordUndefs) { } void SymbolConverter::visitGlobal(const GlobalRecord &GR) { - auto [SymName, SymKind] = parseSymbol(GR.getName(), GR.getFlags()); + auto [SymName, SymKind, InterfaceType] = parseSymbol(GR.getName()); if (shouldSkipRecord(GR, RecordUndefs)) return; Symbols->addGlobal(SymKind, SymName, GR.getFlags(), Targ); + + if (InterfaceType == ObjCIFSymbolKind::None) { + Symbols->addGlobal(SymKind, SymName, GR.getFlags(), Targ); + return; + } + + // It is impossible to hold a complete ObjCInterface with a single + // GlobalRecord, so continue to treat this symbol a generic global. + Symbols->addGlobal(EncodeKind::GlobalSymbol, GR.getName(), GR.getFlags(), + Targ); } void SymbolConverter::addIVars(const ArrayRef<ObjCIVarRecord *> IVars, @@ -48,11 +58,28 @@ void SymbolConverter::addIVars(const ArrayRef<ObjCIVarRecord *> IVars, void SymbolConverter::visitObjCInterface(const ObjCInterfaceRecord &ObjCR) { if (!shouldSkipRecord(ObjCR, RecordUndefs)) { - Symbols->addGlobal(EncodeKind::ObjectiveCClass, ObjCR.getName(), - ObjCR.getFlags(), Targ); - if (ObjCR.hasExceptionAttribute()) - Symbols->addGlobal(EncodeKind::ObjectiveCClassEHType, ObjCR.getName(), + if (ObjCR.isCompleteInterface()) { + Symbols->addGlobal(EncodeKind::ObjectiveCClass, ObjCR.getName(), ObjCR.getFlags(), Targ); + if (ObjCR.hasExceptionAttribute()) + Symbols->addGlobal(EncodeKind::ObjectiveCClassEHType, ObjCR.getName(), + ObjCR.getFlags(), Targ); + } else { + // Because there is not a complete interface, visit individual symbols + // instead. + if (ObjCR.isExportedSymbol(ObjCIFSymbolKind::EHType)) + Symbols->addGlobal(EncodeKind::GlobalSymbol, + (ObjC2EHTypePrefix + ObjCR.getName()).str(), + ObjCR.getFlags(), Targ); + if (ObjCR.isExportedSymbol(ObjCIFSymbolKind::Class)) + Symbols->addGlobal(EncodeKind::GlobalSymbol, + (ObjC2ClassNamePrefix + ObjCR.getName()).str(), + ObjCR.getFlags(), Targ); + if (ObjCR.isExportedSymbol(ObjCIFSymbolKind::MetaClass)) + Symbols->addGlobal(EncodeKind::GlobalSymbol, + (ObjC2MetaClassNamePrefix + ObjCR.getName()).str(), + ObjCR.getFlags(), Targ); + } } addIVars(ObjCR.getObjCIVars(), ObjCR.getName()); diff --git a/llvm/lib/TextAPI/RecordsSlice.cpp b/llvm/lib/TextAPI/RecordsSlice.cpp index 7f6fad17..f07853e 100644 --- a/llvm/lib/TextAPI/RecordsSlice.cpp +++ b/llvm/lib/TextAPI/RecordsSlice.cpp @@ -22,15 +22,21 @@ using namespace llvm::MachO; Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags, GlobalRecord::Kind GV, RecordLinkage Linkage) { // Find a specific Record type to capture. - auto [APIName, SymKind] = parseSymbol(Name, Flags); + auto [APIName, SymKind, InterfaceType] = parseSymbol(Name); Name = APIName; switch (SymKind) { case EncodeKind::GlobalSymbol: return addGlobal(Name, Linkage, GV, Flags); case EncodeKind::ObjectiveCClass: - return addObjCInterface(Name, Linkage); - case EncodeKind::ObjectiveCClassEHType: - return addObjCInterface(Name, Linkage, /*HasEHType=*/true); + return addObjCInterface(Name, Linkage, InterfaceType); + case EncodeKind::ObjectiveCClassEHType: { + ObjCInterfaceRecord *Rec = addObjCInterface(Name, Linkage, InterfaceType); + // When classes without ehtype are used in try/catch blocks + // a weak-defined symbol is exported. + if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined) + updateFlags(Rec, SymbolFlags::WeakDefined); + return Rec; + } case EncodeKind::ObjectiveCInstanceVariable: { auto [Super, IVar] = Name.split('.'); // Attempt to find super class. @@ -88,6 +94,39 @@ GlobalRecord *RecordsSlice::findGlobal(StringRef Name, return Record; } +RecordLinkage +ObjCInterfaceRecord::getLinkageForSymbol(ObjCIFSymbolKind CurrType) const { + assert(CurrType <= ObjCIFSymbolKind::EHType && + "expected single ObjCIFSymbolKind enum value"); + if (CurrType == ObjCIFSymbolKind::Class) + return Linkages.Class; + + if (CurrType == ObjCIFSymbolKind::MetaClass) + return Linkages.MetaClass; + + if (CurrType == ObjCIFSymbolKind::EHType) + return Linkages.EHType; + + llvm_unreachable("unexpected ObjCIFSymbolKind"); +} + +void ObjCInterfaceRecord::updateLinkageForSymbols(ObjCIFSymbolKind SymType, + RecordLinkage Link) { + if ((SymType & ObjCIFSymbolKind::Class) == ObjCIFSymbolKind::Class) + Linkages.Class = std::max(Link, Linkages.Class); + if ((SymType & ObjCIFSymbolKind::MetaClass) == ObjCIFSymbolKind::MetaClass) + Linkages.MetaClass = std::max(Link, Linkages.MetaClass); + if ((SymType & ObjCIFSymbolKind::EHType) == ObjCIFSymbolKind::EHType) + Linkages.EHType = std::max(Link, Linkages.EHType); + + // Obj-C Classes represent multiple symbols that could have competing + // linkages, in this case assign the largest one, when querying the linkage of + // the record itself. This allows visitors pick whether they want to account + // for complete symbol information. + Linkage = + std::max(Linkages.Class, std::max(Linkages.MetaClass, Linkages.EHType)); +} + ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const { return findRecord<ObjCInterfaceRecord>(Name, Classes); } @@ -152,21 +191,17 @@ GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage, ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name, RecordLinkage Linkage, - bool HasEHType) { + ObjCIFSymbolKind SymType) { Name = copyString(Name); auto Result = Classes.insert({Name, nullptr}); - if (Result.second) { + if (Result.second) Result.first->second = - std::make_unique<ObjCInterfaceRecord>(Name, Linkage, HasEHType); - } else { - // ObjC classes represent multiple symbols that could have competing - // linkages, in those cases assign the largest one. - if (Linkage >= RecordLinkage::Rexported) - updateLinkage(Result.first->second.get(), Linkage); - } - + std::make_unique<ObjCInterfaceRecord>(Name, Linkage, SymType); + else + Result.first->second->updateLinkageForSymbols(SymType, Linkage); return Result.first->second.get(); } + SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) { // Add Linkage properties into Flags. switch (Linkage) { diff --git a/llvm/lib/TextAPI/Symbol.cpp b/llvm/lib/TextAPI/Symbol.cpp index e67627e..c899821 100644 --- a/llvm/lib/TextAPI/Symbol.cpp +++ b/llvm/lib/TextAPI/Symbol.cpp @@ -72,30 +72,23 @@ bool Symbol::operator==(const Symbol &O) const { std::tie(O.Name, O.Kind, O.Targets, RHSFlags); } -SimpleSymbol parseSymbol(StringRef SymName, const SymbolFlags Flags) { +SimpleSymbol parseSymbol(StringRef SymName) { if (SymName.starts_with(ObjC1ClassNamePrefix)) return {SymName.drop_front(ObjC1ClassNamePrefix.size()), - EncodeKind::ObjectiveCClass}; + EncodeKind::ObjectiveCClass, ObjCIFSymbolKind::Class}; if (SymName.starts_with(ObjC2ClassNamePrefix)) return {SymName.drop_front(ObjC2ClassNamePrefix.size()), - EncodeKind::ObjectiveCClass}; + EncodeKind::ObjectiveCClass, ObjCIFSymbolKind::Class}; if (SymName.starts_with(ObjC2MetaClassNamePrefix)) return {SymName.drop_front(ObjC2MetaClassNamePrefix.size()), - EncodeKind::ObjectiveCClass}; - if (SymName.starts_with(ObjC2EHTypePrefix)) { - // When classes without ehtype are used in try/catch blocks - // a weak-defined symbol is exported. In those cases, treat these as a - // global instead. - if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined) - return {SymName, EncodeKind::GlobalSymbol}; + EncodeKind::ObjectiveCClass, ObjCIFSymbolKind::MetaClass}; + if (SymName.starts_with(ObjC2EHTypePrefix)) return {SymName.drop_front(ObjC2EHTypePrefix.size()), - EncodeKind::ObjectiveCClassEHType}; - } - + EncodeKind::ObjectiveCClassEHType, ObjCIFSymbolKind::EHType}; if (SymName.starts_with(ObjC2IVarPrefix)) return {SymName.drop_front(ObjC2IVarPrefix.size()), - EncodeKind::ObjectiveCInstanceVariable}; - return {SymName, EncodeKind::GlobalSymbol}; + EncodeKind::ObjectiveCInstanceVariable, ObjCIFSymbolKind::None}; + return {SymName, EncodeKind::GlobalSymbol, ObjCIFSymbolKind::None}; } } // end namespace MachO. diff --git a/llvm/lib/TextAPI/SymbolSet.cpp b/llvm/lib/TextAPI/SymbolSet.cpp index 0cbfa2f..2e0b416 100644 --- a/llvm/lib/TextAPI/SymbolSet.cpp +++ b/llvm/lib/TextAPI/SymbolSet.cpp @@ -28,6 +28,21 @@ Symbol *SymbolSet::addGlobal(EncodeKind Kind, StringRef Name, SymbolFlags Flags, return Sym; } -const Symbol *SymbolSet::findSymbol(EncodeKind Kind, StringRef Name) const { - return Symbols.lookup({Kind, Name}); +const Symbol *SymbolSet::findSymbol(EncodeKind Kind, StringRef Name, + ObjCIFSymbolKind ObjCIF) const { + if (auto result = Symbols.lookup({Kind, Name})) + return result; + if ((ObjCIF == ObjCIFSymbolKind::None) || (ObjCIF > ObjCIFSymbolKind::EHType)) + return nullptr; + assert(ObjCIF <= ObjCIFSymbolKind::EHType && + "expected single ObjCIFSymbolKind enum value"); + // Non-complete ObjC Interfaces are represented as global symbols. + if (ObjCIF == ObjCIFSymbolKind::Class) + return Symbols.lookup( + {EncodeKind::GlobalSymbol, (ObjC2ClassNamePrefix + Name).str()}); + if (ObjCIF == ObjCIFSymbolKind::MetaClass) + return Symbols.lookup( + {EncodeKind::GlobalSymbol, (ObjC2MetaClassNamePrefix + Name).str()}); + return Symbols.lookup( + {EncodeKind::GlobalSymbol, (ObjC2EHTypePrefix + Name).str()}); } |