Skip to content

Commit 4460fa8

Browse files
authored
[TextAPI] Introduce granularity for handling ObjC Interface symbols (llvm#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
1 parent 45188c6 commit 4460fa8

File tree

12 files changed

+1134
-55
lines changed

12 files changed

+1134
-55
lines changed

llvm/include/llvm/TextAPI/InterfaceFile.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,9 +351,11 @@ class InterfaceFile {
351351
///
352352
/// \param Kind The kind of global symbol to record.
353353
/// \param Name The name of the symbol.
354-
std::optional<const Symbol *> getSymbol(EncodeKind Kind,
355-
StringRef Name) const {
356-
if (auto *Sym = SymbolsSet->findSymbol(Kind, Name))
354+
/// \param ObjCIF The ObjCInterface symbol type, if applicable.
355+
std::optional<const Symbol *>
356+
getSymbol(EncodeKind Kind, StringRef Name,
357+
ObjCIFSymbolKind ObjCIF = ObjCIFSymbolKind::None) const {
358+
if (auto *Sym = SymbolsSet->findSymbol(Kind, Name, ObjCIF))
357359
return Sym;
358360
return std::nullopt;
359361
}

llvm/include/llvm/TextAPI/Record.h

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,15 +164,42 @@ class ObjCCategoryRecord : public ObjCContainerRecord {
164164
class ObjCInterfaceRecord : public ObjCContainerRecord {
165165
public:
166166
ObjCInterfaceRecord(StringRef Name, RecordLinkage Linkage,
167-
bool HasEHType = false)
168-
: ObjCContainerRecord(Name, Linkage), HasEHType(HasEHType) {}
167+
ObjCIFSymbolKind SymType)
168+
: ObjCContainerRecord(Name, Linkage) {
169+
updateLinkageForSymbols(SymType, Linkage);
170+
}
171+
172+
bool hasExceptionAttribute() const {
173+
return Linkages.EHType != RecordLinkage::Unknown;
174+
}
175+
bool isCompleteInterface() const {
176+
return Linkages.Class >= RecordLinkage::Rexported &&
177+
Linkages.MetaClass >= RecordLinkage::Rexported;
178+
}
179+
bool isExportedSymbol(ObjCIFSymbolKind CurrType) const {
180+
return getLinkageForSymbol(CurrType) >= RecordLinkage::Rexported;
181+
}
182+
183+
RecordLinkage getLinkageForSymbol(ObjCIFSymbolKind CurrType) const;
184+
void updateLinkageForSymbols(ObjCIFSymbolKind SymType, RecordLinkage Link);
169185

170-
bool hasExceptionAttribute() const { return HasEHType; }
171186
bool addObjCCategory(ObjCCategoryRecord *Record);
172187
std::vector<ObjCCategoryRecord *> getObjCCategories() const;
173188

174189
private:
175-
bool HasEHType;
190+
/// Linkage level for each symbol represented in ObjCInterfaceRecord.
191+
struct Linkages {
192+
RecordLinkage Class = RecordLinkage::Unknown;
193+
RecordLinkage MetaClass = RecordLinkage::Unknown;
194+
RecordLinkage EHType = RecordLinkage::Unknown;
195+
bool operator==(const Linkages &other) const {
196+
return std::tie(Class, MetaClass, EHType) ==
197+
std::tie(other.Class, other.MetaClass, other.EHType);
198+
}
199+
bool operator!=(const Linkages &other) const { return !(*this == other); }
200+
};
201+
Linkages Linkages;
202+
176203
// Non-owning containers of categories that extend the class.
177204
llvm::MapVector<StringRef, ObjCCategoryRecord *> Categories;
178205
};

llvm/include/llvm/TextAPI/RecordsSlice.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ class RecordsSlice {
6262
///
6363
/// \param Name The name of class, not symbol.
6464
/// \param Linkage The linkage of symbol.
65-
/// \param HasEHType Whether symbol represents an eh_type.
65+
/// \param SymType The symbols this class represents.
6666
/// \return The non-owning pointer to added record in slice.
6767
ObjCInterfaceRecord *addObjCInterface(StringRef Name, RecordLinkage Linkage,
68-
bool HasEHType = false);
68+
ObjCIFSymbolKind SymType);
6969

7070
/// Add ObjC IVar record.
7171
///
@@ -179,9 +179,9 @@ class RecordsSlice {
179179

180180
/// Update set flags of requested record.
181181
///
182-
/// \param R The global record to update.
182+
/// \param R The record to update.
183183
/// \param F Flags to update to.
184-
void updateFlags(GlobalRecord *R, SymbolFlags F) { R->Flags = F; }
184+
void updateFlags(Record *R, SymbolFlags F) { R->Flags |= F; }
185185

186186
RecordMap<GlobalRecord> Globals;
187187
RecordMap<ObjCInterfaceRecord> Classes;

llvm/include/llvm/TextAPI/Symbol.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,19 @@ constexpr StringLiteral ObjC2MetaClassNamePrefix = "_OBJC_METACLASS_$_";
6565
constexpr StringLiteral ObjC2EHTypePrefix = "_OBJC_EHTYPE_$_";
6666
constexpr StringLiteral ObjC2IVarPrefix = "_OBJC_IVAR_$_";
6767

68+
/// ObjC Interface symbol mappings.
69+
enum class ObjCIFSymbolKind : uint8_t {
70+
None = 0,
71+
/// Is OBJC_CLASS* symbol.
72+
Class = 1U << 0,
73+
/// Is OBJC_METACLASS* symbol.
74+
MetaClass = 1U << 1,
75+
/// Is OBJC_EHTYPE* symbol.
76+
EHType = 1U << 2,
77+
78+
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/EHType),
79+
};
80+
6881
using TargetList = SmallVector<Target, 5>;
6982

7083
// Keep containers that hold Targets in sorted order and uniqued.
@@ -165,18 +178,18 @@ class Symbol {
165178
struct SimpleSymbol {
166179
StringRef Name;
167180
EncodeKind Kind;
181+
ObjCIFSymbolKind ObjCInterfaceType;
168182

169183
bool operator<(const SimpleSymbol &O) const {
170-
return std::tie(Name, Kind) < std::tie(O.Name, O.Kind);
184+
return std::tie(Name, Kind, ObjCInterfaceType) <
185+
std::tie(O.Name, O.Kind, O.ObjCInterfaceType);
171186
}
172187
};
173188

174-
/// Determine EncodeKind from Flags and parsing Name.
189+
/// Get symbol classification by parsing the name of a symbol.
175190
///
176191
/// \param Name The name of symbol.
177-
/// \param Flags The flags pre-determined for the symbol.
178-
SimpleSymbol parseSymbol(StringRef SymName,
179-
const SymbolFlags Flags = SymbolFlags::None);
192+
SimpleSymbol parseSymbol(StringRef SymName);
180193

181194
} // end namespace MachO.
182195
} // end namespace llvm.

llvm/include/llvm/TextAPI/SymbolSet.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ class SymbolSet {
107107
return Global;
108108
}
109109

110-
const Symbol *findSymbol(EncodeKind Kind, StringRef Name) const;
110+
const Symbol *
111+
findSymbol(EncodeKind Kind, StringRef Name,
112+
ObjCIFSymbolKind ObjCIF = ObjCIFSymbolKind::None) const;
111113

112114
struct const_symbol_iterator
113115
: public iterator_adaptor_base<

llvm/lib/TextAPI/RecordVisitor.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,20 @@ static bool shouldSkipRecord(const Record &R, const bool RecordUndefs) {
2828
}
2929

3030
void SymbolConverter::visitGlobal(const GlobalRecord &GR) {
31-
auto [SymName, SymKind] = parseSymbol(GR.getName(), GR.getFlags());
31+
auto [SymName, SymKind, InterfaceType] = parseSymbol(GR.getName());
3232
if (shouldSkipRecord(GR, RecordUndefs))
3333
return;
3434
Symbols->addGlobal(SymKind, SymName, GR.getFlags(), Targ);
35+
36+
if (InterfaceType == ObjCIFSymbolKind::None) {
37+
Symbols->addGlobal(SymKind, SymName, GR.getFlags(), Targ);
38+
return;
39+
}
40+
41+
// It is impossible to hold a complete ObjCInterface with a single
42+
// GlobalRecord, so continue to treat this symbol a generic global.
43+
Symbols->addGlobal(EncodeKind::GlobalSymbol, GR.getName(), GR.getFlags(),
44+
Targ);
3545
}
3646

3747
void SymbolConverter::addIVars(const ArrayRef<ObjCIVarRecord *> IVars,
@@ -48,11 +58,28 @@ void SymbolConverter::addIVars(const ArrayRef<ObjCIVarRecord *> IVars,
4858

4959
void SymbolConverter::visitObjCInterface(const ObjCInterfaceRecord &ObjCR) {
5060
if (!shouldSkipRecord(ObjCR, RecordUndefs)) {
51-
Symbols->addGlobal(EncodeKind::ObjectiveCClass, ObjCR.getName(),
52-
ObjCR.getFlags(), Targ);
53-
if (ObjCR.hasExceptionAttribute())
54-
Symbols->addGlobal(EncodeKind::ObjectiveCClassEHType, ObjCR.getName(),
61+
if (ObjCR.isCompleteInterface()) {
62+
Symbols->addGlobal(EncodeKind::ObjectiveCClass, ObjCR.getName(),
5563
ObjCR.getFlags(), Targ);
64+
if (ObjCR.hasExceptionAttribute())
65+
Symbols->addGlobal(EncodeKind::ObjectiveCClassEHType, ObjCR.getName(),
66+
ObjCR.getFlags(), Targ);
67+
} else {
68+
// Because there is not a complete interface, visit individual symbols
69+
// instead.
70+
if (ObjCR.isExportedSymbol(ObjCIFSymbolKind::EHType))
71+
Symbols->addGlobal(EncodeKind::GlobalSymbol,
72+
(ObjC2EHTypePrefix + ObjCR.getName()).str(),
73+
ObjCR.getFlags(), Targ);
74+
if (ObjCR.isExportedSymbol(ObjCIFSymbolKind::Class))
75+
Symbols->addGlobal(EncodeKind::GlobalSymbol,
76+
(ObjC2ClassNamePrefix + ObjCR.getName()).str(),
77+
ObjCR.getFlags(), Targ);
78+
if (ObjCR.isExportedSymbol(ObjCIFSymbolKind::MetaClass))
79+
Symbols->addGlobal(EncodeKind::GlobalSymbol,
80+
(ObjC2MetaClassNamePrefix + ObjCR.getName()).str(),
81+
ObjCR.getFlags(), Targ);
82+
}
5683
}
5784

5885
addIVars(ObjCR.getObjCIVars(), ObjCR.getName());

llvm/lib/TextAPI/RecordsSlice.cpp

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,21 @@ using namespace llvm::MachO;
2222
Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags,
2323
GlobalRecord::Kind GV, RecordLinkage Linkage) {
2424
// Find a specific Record type to capture.
25-
auto [APIName, SymKind] = parseSymbol(Name, Flags);
25+
auto [APIName, SymKind, InterfaceType] = parseSymbol(Name);
2626
Name = APIName;
2727
switch (SymKind) {
2828
case EncodeKind::GlobalSymbol:
2929
return addGlobal(Name, Linkage, GV, Flags);
3030
case EncodeKind::ObjectiveCClass:
31-
return addObjCInterface(Name, Linkage);
32-
case EncodeKind::ObjectiveCClassEHType:
33-
return addObjCInterface(Name, Linkage, /*HasEHType=*/true);
31+
return addObjCInterface(Name, Linkage, InterfaceType);
32+
case EncodeKind::ObjectiveCClassEHType: {
33+
ObjCInterfaceRecord *Rec = addObjCInterface(Name, Linkage, InterfaceType);
34+
// When classes without ehtype are used in try/catch blocks
35+
// a weak-defined symbol is exported.
36+
if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined)
37+
updateFlags(Rec, SymbolFlags::WeakDefined);
38+
return Rec;
39+
}
3440
case EncodeKind::ObjectiveCInstanceVariable: {
3541
auto [Super, IVar] = Name.split('.');
3642
// Attempt to find super class.
@@ -88,6 +94,39 @@ GlobalRecord *RecordsSlice::findGlobal(StringRef Name,
8894
return Record;
8995
}
9096

97+
RecordLinkage
98+
ObjCInterfaceRecord::getLinkageForSymbol(ObjCIFSymbolKind CurrType) const {
99+
assert(CurrType <= ObjCIFSymbolKind::EHType &&
100+
"expected single ObjCIFSymbolKind enum value");
101+
if (CurrType == ObjCIFSymbolKind::Class)
102+
return Linkages.Class;
103+
104+
if (CurrType == ObjCIFSymbolKind::MetaClass)
105+
return Linkages.MetaClass;
106+
107+
if (CurrType == ObjCIFSymbolKind::EHType)
108+
return Linkages.EHType;
109+
110+
llvm_unreachable("unexpected ObjCIFSymbolKind");
111+
}
112+
113+
void ObjCInterfaceRecord::updateLinkageForSymbols(ObjCIFSymbolKind SymType,
114+
RecordLinkage Link) {
115+
if ((SymType & ObjCIFSymbolKind::Class) == ObjCIFSymbolKind::Class)
116+
Linkages.Class = std::max(Link, Linkages.Class);
117+
if ((SymType & ObjCIFSymbolKind::MetaClass) == ObjCIFSymbolKind::MetaClass)
118+
Linkages.MetaClass = std::max(Link, Linkages.MetaClass);
119+
if ((SymType & ObjCIFSymbolKind::EHType) == ObjCIFSymbolKind::EHType)
120+
Linkages.EHType = std::max(Link, Linkages.EHType);
121+
122+
// Obj-C Classes represent multiple symbols that could have competing
123+
// linkages, in this case assign the largest one, when querying the linkage of
124+
// the record itself. This allows visitors pick whether they want to account
125+
// for complete symbol information.
126+
Linkage =
127+
std::max(Linkages.Class, std::max(Linkages.MetaClass, Linkages.EHType));
128+
}
129+
91130
ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {
92131
return findRecord<ObjCInterfaceRecord>(Name, Classes);
93132
}
@@ -152,21 +191,17 @@ GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
152191

153192
ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,
154193
RecordLinkage Linkage,
155-
bool HasEHType) {
194+
ObjCIFSymbolKind SymType) {
156195
Name = copyString(Name);
157196
auto Result = Classes.insert({Name, nullptr});
158-
if (Result.second) {
197+
if (Result.second)
159198
Result.first->second =
160-
std::make_unique<ObjCInterfaceRecord>(Name, Linkage, HasEHType);
161-
} else {
162-
// ObjC classes represent multiple symbols that could have competing
163-
// linkages, in those cases assign the largest one.
164-
if (Linkage >= RecordLinkage::Rexported)
165-
updateLinkage(Result.first->second.get(), Linkage);
166-
}
167-
199+
std::make_unique<ObjCInterfaceRecord>(Name, Linkage, SymType);
200+
else
201+
Result.first->second->updateLinkageForSymbols(SymType, Linkage);
168202
return Result.first->second.get();
169203
}
204+
170205
SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) {
171206
// Add Linkage properties into Flags.
172207
switch (Linkage) {

llvm/lib/TextAPI/Symbol.cpp

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,30 +72,23 @@ bool Symbol::operator==(const Symbol &O) const {
7272
std::tie(O.Name, O.Kind, O.Targets, RHSFlags);
7373
}
7474

75-
SimpleSymbol parseSymbol(StringRef SymName, const SymbolFlags Flags) {
75+
SimpleSymbol parseSymbol(StringRef SymName) {
7676
if (SymName.starts_with(ObjC1ClassNamePrefix))
7777
return {SymName.drop_front(ObjC1ClassNamePrefix.size()),
78-
EncodeKind::ObjectiveCClass};
78+
EncodeKind::ObjectiveCClass, ObjCIFSymbolKind::Class};
7979
if (SymName.starts_with(ObjC2ClassNamePrefix))
8080
return {SymName.drop_front(ObjC2ClassNamePrefix.size()),
81-
EncodeKind::ObjectiveCClass};
81+
EncodeKind::ObjectiveCClass, ObjCIFSymbolKind::Class};
8282
if (SymName.starts_with(ObjC2MetaClassNamePrefix))
8383
return {SymName.drop_front(ObjC2MetaClassNamePrefix.size()),
84-
EncodeKind::ObjectiveCClass};
85-
if (SymName.starts_with(ObjC2EHTypePrefix)) {
86-
// When classes without ehtype are used in try/catch blocks
87-
// a weak-defined symbol is exported. In those cases, treat these as a
88-
// global instead.
89-
if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined)
90-
return {SymName, EncodeKind::GlobalSymbol};
84+
EncodeKind::ObjectiveCClass, ObjCIFSymbolKind::MetaClass};
85+
if (SymName.starts_with(ObjC2EHTypePrefix))
9186
return {SymName.drop_front(ObjC2EHTypePrefix.size()),
92-
EncodeKind::ObjectiveCClassEHType};
93-
}
94-
87+
EncodeKind::ObjectiveCClassEHType, ObjCIFSymbolKind::EHType};
9588
if (SymName.starts_with(ObjC2IVarPrefix))
9689
return {SymName.drop_front(ObjC2IVarPrefix.size()),
97-
EncodeKind::ObjectiveCInstanceVariable};
98-
return {SymName, EncodeKind::GlobalSymbol};
90+
EncodeKind::ObjectiveCInstanceVariable, ObjCIFSymbolKind::None};
91+
return {SymName, EncodeKind::GlobalSymbol, ObjCIFSymbolKind::None};
9992
}
10093

10194
} // end namespace MachO.

llvm/lib/TextAPI/SymbolSet.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,21 @@ Symbol *SymbolSet::addGlobal(EncodeKind Kind, StringRef Name, SymbolFlags Flags,
2828
return Sym;
2929
}
3030

31-
const Symbol *SymbolSet::findSymbol(EncodeKind Kind, StringRef Name) const {
32-
return Symbols.lookup({Kind, Name});
31+
const Symbol *SymbolSet::findSymbol(EncodeKind Kind, StringRef Name,
32+
ObjCIFSymbolKind ObjCIF) const {
33+
if (auto result = Symbols.lookup({Kind, Name}))
34+
return result;
35+
if ((ObjCIF == ObjCIFSymbolKind::None) || (ObjCIF > ObjCIFSymbolKind::EHType))
36+
return nullptr;
37+
assert(ObjCIF <= ObjCIFSymbolKind::EHType &&
38+
"expected single ObjCIFSymbolKind enum value");
39+
// Non-complete ObjC Interfaces are represented as global symbols.
40+
if (ObjCIF == ObjCIFSymbolKind::Class)
41+
return Symbols.lookup(
42+
{EncodeKind::GlobalSymbol, (ObjC2ClassNamePrefix + Name).str()});
43+
if (ObjCIF == ObjCIFSymbolKind::MetaClass)
44+
return Symbols.lookup(
45+
{EncodeKind::GlobalSymbol, (ObjC2MetaClassNamePrefix + Name).str()});
46+
return Symbols.lookup(
47+
{EncodeKind::GlobalSymbol, (ObjC2EHTypePrefix + Name).str()});
3348
}

0 commit comments

Comments
 (0)