[lld] [llvm] [lld-macho] Implement ObjC category merging (-objc_category_merging) (PR #82928)
Vincent Lee via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 18 02:29:28 PDT 2024
================
@@ -320,3 +332,904 @@ void objc::checkCategories() {
}
}
}
+
+namespace {
+
+class ObjcCategoryMerger {
+ // Information about an input category
+ struct InfoInputCategory {
+ ConcatInputSection *catListIsec;
+ ConcatInputSection *catBodyIsec;
+ uint32_t offCatListIsec = 0;
+
+ bool wasMerged = false;
+ };
+
+ // To write new (merged) categories or classes, we will try make limited
+ // assumptions about the alignment and the sections the various class/category
+ // info are stored in and . So we'll just reuse the same sections and
+ // alignment as already used in existing (input) categories. To do this we
+ // have InfoCategoryWriter which contains the various sections that the
+ // generated categories will be written to.
+ template <typename T> struct InfoWriteSection {
+ bool valid = false; // Data has been successfully collected from input
+ uint32_t align = 0;
+ Section *inputSection;
+ Reloc relocTemplate;
+ T *outputSection;
+ };
+
+ struct InfoCategoryWriter {
+ InfoWriteSection<ConcatOutputSection> catListInfo;
+ InfoWriteSection<ConcatOutputSection> catBodyInfo;
+ InfoWriteSection<CStringSection> catNameInfo;
+ InfoWriteSection<ConcatOutputSection> catPtrListInfo;
+ };
+
+ // Information about a pointer list in the original categories (method lists,
+ // protocol lists, etc)
+ struct PointerListInfo {
+ PointerListInfo(const char *_categoryPrefix, uint32_t _categoryOffset,
+ uint32_t _pointersPerStruct)
+ : categoryPrefix(_categoryPrefix), categoryOffset(_categoryOffset),
+ pointersPerStruct(_pointersPerStruct) {}
+ const char *categoryPrefix;
+ uint32_t categoryOffset = 0;
+
+ uint32_t pointersPerStruct = 0;
+
+ uint32_t structSize = 0;
+ uint32_t structCount = 0;
+
+ std::vector<Symbol *> allPtrs;
+ };
+
+ // Full information about all the categories that extend a class. This will
+ // include all the additional methods, protocols, and properties that are
+ // contained in all the categories that extend a particular class.
+ struct ClassExtensionInfo {
+ ClassExtensionInfo(CategoryLayout &_catLayout) : catLayout(_catLayout){};
+
+ // Merged names of containers. Ex: base|firstCategory|secondCategory|...
+ std::string mergedContainerName;
+ std::string baseClassName;
+ Symbol *baseClass = nullptr;
+ CategoryLayout &catLayout;
+
+ // In case we generate new data, mark the new data as belonging to this file
+ ObjFile *objFileForMergeData = nullptr;
+
+ PointerListInfo instanceMethods = {
+ objc::symbol_names::categoryInstanceMethods,
+ /*_categoryOffset=*/catLayout.instanceMethodsOffset,
+ /*pointersPerStruct=*/3};
+ PointerListInfo classMethods = {
+ objc::symbol_names::categoryClassMethods,
+ /*_categoryOffset=*/catLayout.classMethodsOffset,
+ /*pointersPerStruct=*/3};
+ PointerListInfo protocols = {objc::symbol_names::categoryProtocols,
+ /*_categoryOffset=*/catLayout.protocolsOffset,
+ /*pointersPerStruct=*/0};
+ PointerListInfo instanceProps = {
+ objc::symbol_names::listProprieties,
+ /*_categoryOffset=*/catLayout.instancePropsOffset,
+ /*pointersPerStruct=*/2};
+ PointerListInfo classProps = {
+ objc::symbol_names::klassPropList,
+ /*_categoryOffset=*/catLayout.classPropsOffset,
+ /*pointersPerStruct=*/2};
+ };
+
+public:
+ ObjcCategoryMerger(std::vector<ConcatInputSection *> &_allInputSections);
+ void doMerge();
+ static void doCleanup();
+
+private:
+ void collectAndValidateCategoriesData();
+ void
+ mergeCategoriesIntoSingleCategory(std::vector<InfoInputCategory> &categories);
+
+ void eraseISec(ConcatInputSection *isec);
+ void eraseMergedCategories();
+
+ void generateCatListForNonErasedCategories(
+ std::map<ConcatInputSection *, std::set<uint64_t>>
+ catListToErasedOffsets);
+ template <typename T>
+ void collectSectionWriteInfoFromIsec(const InputSection *isec,
+ InfoWriteSection<T> &catWriteInfo);
+ void collectCategoryWriterInfoFromCategory(const InfoInputCategory &catInfo);
+ void parseCatInfoToExtInfo(const InfoInputCategory &catInfo,
+ ClassExtensionInfo &extInfo);
+
+ void parseProtocolListInfo(const ConcatInputSection *isec, uint32_t secOffset,
+ PointerListInfo &ptrList);
+
+ void parsePointerListInfo(const ConcatInputSection *isec, uint32_t secOffset,
+ PointerListInfo &ptrList);
+
+ void emitAndLinkPointerList(Defined *parentSym, uint32_t linkAtOffset,
+ const ClassExtensionInfo &extInfo,
+ const PointerListInfo &ptrList);
+
+ void emitAndLinkProtocolList(Defined *parentSym, uint32_t linkAtOffset,
+ const ClassExtensionInfo &extInfo,
+ const PointerListInfo &ptrList);
+
+ Defined *emitCategory(const ClassExtensionInfo &extInfo);
+ Defined *emitCatListEntrySec(const std::string &forCateogryName,
+ const std::string &forBaseClassName,
+ ObjFile *objFile);
+ Defined *emitCategoryBody(const std::string &name, const Defined *nameSym,
+ const Symbol *baseClassSym,
+ const std::string &baseClassName, ObjFile *objFile);
+ Defined *emitCategoryName(const std::string &name, ObjFile *objFile);
+ void createSymbolReference(Defined *refFrom, const Symbol *refTo,
+ uint32_t offset, const Reloc &relocTemplate);
+ Symbol *tryGetSymbolAtIsecOffset(const ConcatInputSection *isec,
+ uint32_t offset);
+ Defined *tryGetDefinedAtIsecOffset(const ConcatInputSection *isec,
+ uint32_t offset);
+ void tryEraseDefinedAtIsecOffset(const ConcatInputSection *isec,
+ uint32_t offset);
+
+ // Allocate a null-terminated StringRef backed by generatedSectionData
+ StringRef newStringData(const char *str);
+ // Allocate section data, backed by generatedSectionData
+ SmallVector<uint8_t> &newSectionData(uint32_t size);
+
+ CategoryLayout catLayout;
+ ClassLayout classLayout;
+ ROClassLayout roClassLayout;
+ ListHeaderLayout listHeaderLayout;
+ MethodLayout methodLayout;
+ ProtocolListHeaderLayout protocolListHeaderLayout;
+
+ InfoCategoryWriter infoCategoryWriter;
+ std::vector<ConcatInputSection *> &allInputSections;
+ // Map of base class Symbol to list of InfoInputCategory's for it
+ std::map<const Symbol *, std::vector<InfoInputCategory>> categoryMap;
----------------
thevinster wrote:
Any reason not to use DenseMap?
https://github.com/llvm/llvm-project/pull/82928
More information about the llvm-commits
mailing list