From 873584b6cb811b0245d79b5dba52758d3d049bb8 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Tue, 8 Nov 2022 17:40:11 -0800 Subject: [PATCH] [ORC-RT][MachO] Add RecordSectionsTracker utility to track metadata sections. Newly added sections can be processed by calling processNewSections. Calling reset moves all sections back to the "new" state for reprocessing (expected to be used by dlclose). --- compiler-rt/lib/orc/macho_platform.cpp | 274 +++++++++++++++++++-------------- 1 file changed, 155 insertions(+), 119 deletions(-) diff --git a/compiler-rt/lib/orc/macho_platform.cpp b/compiler-rt/lib/orc/macho_platform.cpp index f17230c..e99fe87 100644 --- a/compiler-rt/lib/orc/macho_platform.cpp +++ b/compiler-rt/lib/orc/macho_platform.cpp @@ -128,6 +128,90 @@ private: using AtExitsVector = std::vector; + /// Used to manage sections of fixed-sized metadata records (e.g. pointer + /// sections, selector refs, etc.) + template class RecordSectionsTracker { + public: + /// Add a section to the "new" list. + void add(span Sec) { New.push_back(std::move(Sec)); } + + /// Returns true if there are new sections to process. + bool hasNewSections() const { return !New.empty(); } + + /// Process all new sections. + template + std::enable_if_t>>> + processNewSections(ProcessSectionFunc &&ProcessSection) { + for (auto &Sec : New) + ProcessSection(Sec); + moveNewToProcessed(); + } + + /// Proces all new sections with a fallible handler. + /// + /// Successfully handled sections will be moved to the Processed + /// list. + template + std::enable_if_t< + std::is_same_v>>, + Error> + processNewSections(ProcessSectionFunc &&ProcessSection) { + for (size_t I = 0; I != New.size(); ++I) { + if (auto Err = ProcessSection(New[I])) { + for (size_t J = 0; J != I; ++J) + Processed.push_back(New[J]); + New.erase(New.begin(), New.begin() + I); + return Err; + } + } + moveNewToProcessed(); + return Error::success(); + } + + /// Move all sections back to New for reprocessing. + void reset() { + moveNewToProcessed(); + New = std::move(Processed); + } + + /// Remove the section with the given range. + bool removeIfPresent(ExecutorAddrRange R) { + if (removeIfPresent(New, R)) + return true; + return removeIfPresent(Processed, R); + } + + private: + void moveNewToProcessed() { + if (Processed.empty()) + Processed = std::move(New); + else { + Processed.reserve(Processed.size() + New.size()); + std::copy(New.begin(), New.end(), std::back_inserter(Processed)); + New.clear(); + } + } + + bool removeIfPresent(std::vector> &V, + ExecutorAddrRange R) { + auto RI = std::find_if( + V.rbegin(), V.rend(), + [RS = R.toSpan()](const span &E) { + return E.data() == RS.data(); + }); + if (RI != V.rend()) { + V.erase(std::next(RI).base()); + return true; + } + return false; + } + + std::vector> Processed; + std::vector> New; + }; + struct JITDylibState { std::string Name; void *Header = nullptr; @@ -139,18 +223,12 @@ private: const objc_image_info *ObjCImageInfo = nullptr; std::unordered_map> DataSectionContent; std::unordered_map ZeroInitRanges; - std::vector> ModInitsSections; - std::vector> ModInitsSectionsNew; - std::vector> ObjCClassListSections; - std::vector> ObjCClassListSectionsNew; - std::vector> ObjCSelRefsSections; - std::vector> ObjCSelRefsSectionsNew; - std::vector> Swift5ProtocolsSections; - std::vector> Swift5ProtocolsSectionsNew; - std::vector> Swift5ProtocolConformancesSections; - std::vector> Swift5ProtocolConformancesSectionsNew; - std::vector> Swift5TypesSections; - std::vector> Swift5TypesSectionsNew; + RecordSectionsTracker ModInitsSections; + RecordSectionsTracker ObjCClassListSections; + RecordSectionsTracker ObjCSelRefsSections; + RecordSectionsTracker Swift5ProtocolsSections; + RecordSectionsTracker Swift5ProtocolConformancesSections; + RecordSectionsTracker Swift5TypesSections; bool referenced() const { return LinkedAgainstRefCount != 0 || DlRefCount != 0; @@ -356,18 +434,17 @@ Error MachOPlatformRuntimeState::registerObjectPlatformSections( if (auto Err = registerThreadDataSection(KV.second.toSpan())) return Err; } else if (KV.first == "__DATA,__objc_selrefs") - JDS->ObjCSelRefsSectionsNew.push_back(KV.second.toSpan()); + JDS->ObjCSelRefsSections.add(KV.second.toSpan()); else if (KV.first == "__DATA,__objc_classlist") - JDS->ObjCClassListSectionsNew.push_back(KV.second.toSpan()); + JDS->ObjCClassListSections.add(KV.second.toSpan()); else if (KV.first == "__TEXT,__swift5_protos") - JDS->Swift5ProtocolsSectionsNew.push_back(KV.second.toSpan()); + JDS->Swift5ProtocolsSections.add(KV.second.toSpan()); else if (KV.first == "__TEXT,__swift5_proto") - JDS->Swift5ProtocolConformancesSectionsNew.push_back( - KV.second.toSpan()); + JDS->Swift5ProtocolConformancesSections.add(KV.second.toSpan()); else if (KV.first == "__TEXT,__swift5_types") - JDS->Swift5TypesSectionsNew.push_back(KV.second.toSpan()); + JDS->Swift5TypesSections.add(KV.second.toSpan()); else if (KV.first == "__DATA,__mod_init_func") - JDS->ModInitsSectionsNew.push_back(KV.second.toSpan()); + JDS->ModInitsSections.add(KV.second.toSpan()); else { // Should this be a warning instead? return make_error( @@ -380,20 +457,6 @@ Error MachOPlatformRuntimeState::registerObjectPlatformSections( return Error::success(); } -// Remove the given range from the given vector if present. -// Returns true if the range was removed, false otherwise. -template -bool removeIfPresent(std::vector> &V, ExecutorAddrRange R) { - auto RI = std::find_if( - V.rbegin(), V.rend(), - [RS = R.toSpan()](const span &E) { return E.data() == RS.data(); }); - if (RI != V.rend()) { - V.erase(std::next(RI).base()); - return true; - } - return false; -} - Error MachOPlatformRuntimeState::deregisterObjectPlatformSections( ExecutorAddr HeaderAddr, std::vector> Secs) { @@ -432,25 +495,19 @@ Error MachOPlatformRuntimeState::deregisterObjectPlatformSections( if (auto Err = deregisterThreadDataSection(KV.second.toSpan())) return Err; - } else if (KV.first == "__DATA,__objc_selrefs") { - if (!removeIfPresent(JDS->ObjCSelRefsSections, KV.second)) - removeIfPresent(JDS->ObjCSelRefsSectionsNew, KV.second); - } else if (KV.first == "__DATA,__objc_classlist") { - if (!removeIfPresent(JDS->ObjCClassListSections, KV.second)) - removeIfPresent(JDS->ObjCClassListSectionsNew, KV.second); - } else if (KV.first == "__TEXT,__swift5_protos") { - if (!removeIfPresent(JDS->Swift5ProtocolsSections, KV.second)) - removeIfPresent(JDS->Swift5ProtocolsSectionsNew, KV.second); - } else if (KV.first == "__TEXT,__swift5_proto") { - if (!removeIfPresent(JDS->Swift5ProtocolConformancesSections, KV.second)) - removeIfPresent(JDS->Swift5ProtocolConformancesSectionsNew, KV.second); - } else if (KV.first == "__TEXT,__swift5_types") { - if (!removeIfPresent(JDS->Swift5TypesSections, KV.second)) - removeIfPresent(JDS->Swift5TypesSectionsNew, KV.second); - } else if (KV.first == "__DATA,__mod_init_func") { - if (!removeIfPresent(JDS->ModInitsSections, KV.second)) - removeIfPresent(JDS->ModInitsSectionsNew, KV.second); - } else { + } else if (KV.first == "__DATA,__objc_selrefs") + JDS->ObjCSelRefsSections.removeIfPresent(KV.second); + else if (KV.first == "__DATA,__objc_classlist") + JDS->ObjCClassListSections.removeIfPresent(KV.second); + else if (KV.first == "__TEXT,__swift5_protos") + JDS->Swift5ProtocolsSections.removeIfPresent(KV.second); + else if (KV.first == "__TEXT,__swift5_proto") + JDS->Swift5ProtocolConformancesSections.removeIfPresent(KV.second); + else if (KV.first == "__TEXT,__swift5_types") + JDS->Swift5TypesSections.removeIfPresent(KV.second); + else if (KV.first == "__DATA,__mod_init_func") + JDS->ModInitsSections.removeIfPresent(KV.second); + else { // Should this be a warning instead? return make_error( "Encountered unexpected section " + @@ -591,42 +648,26 @@ MachOPlatformRuntimeState::lookupSymbolInJITDylib(void *DSOHandle, return Result; } -template -static void moveAppendSections(std::vector> &Dst, - std::vector> &Src) { - if (Dst.empty()) { - Dst = std::move(Src); - return; - } - - Dst.reserve(Dst.size() + Src.size()); - std::copy(Src.begin(), Src.end(), std::back_inserter(Dst)); - Src.clear(); -} - Error MachOPlatformRuntimeState::registerObjCSelectors(JITDylibState &JDS) { - - if (JDS.ObjCSelRefsSectionsNew.empty()) + if (!JDS.ObjCSelRefsSections.hasNewSections()) return Error::success(); if (ORC_RT_UNLIKELY(!sel_registerName)) return make_error("sel_registerName is not available"); - for (const auto &ObjCSelRefs : JDS.ObjCSelRefsSectionsNew) { - for (uintptr_t &SelEntry : ObjCSelRefs) { + JDS.ObjCSelRefsSections.processNewSections([](span SelRefs) { + for (void *&SelEntry : SelRefs) { const char *SelName = reinterpret_cast(SelEntry); auto Sel = sel_registerName(SelName); *reinterpret_cast(&SelEntry) = Sel; } - } + }); - moveAppendSections(JDS.ObjCSelRefsSections, JDS.ObjCSelRefsSectionsNew); return Error::success(); } Error MachOPlatformRuntimeState::registerObjCClasses(JITDylibState &JDS) { - - if (JDS.ObjCClassListSectionsNew.empty()) + if (!JDS.ObjCClassListSections.hasNewSections()) return Error::success(); if (ORC_RT_UNLIKELY(!objc_msgSend)) @@ -644,91 +685,87 @@ Error MachOPlatformRuntimeState::registerObjCClasses(JITDylibState &JDS) { auto ClassSelector = sel_registerName("class"); - for (const auto &ObjCClassList : JDS.ObjCClassListSectionsNew) { - for (uintptr_t ClassPtr : ObjCClassList) { - auto *Cls = reinterpret_cast(ClassPtr); - auto *ClassCompiled = reinterpret_cast(ClassPtr); - objc_msgSend(reinterpret_cast(ClassCompiled->Parent), ClassSelector); - auto Registered = objc_readClassPair(Cls, JDS.ObjCImageInfo); - - // FIXME: Improve diagnostic by reporting the failed class's name. - if (Registered != Cls) - return make_error("Unable to register Objective-C class"); - } - } - - moveAppendSections(JDS.ObjCClassListSections, JDS.ObjCClassListSectionsNew); - return Error::success(); + return JDS.ObjCClassListSections.processNewSections( + [&](span ClassPtrs) -> Error { + for (void *ClassPtr : ClassPtrs) { + auto *Cls = reinterpret_cast(ClassPtr); + auto *ClassCompiled = reinterpret_cast(ClassPtr); + objc_msgSend(reinterpret_cast(ClassCompiled->Parent), + ClassSelector); + auto Registered = objc_readClassPair(Cls, JDS.ObjCImageInfo); + // FIXME: Improve diagnostic by reporting the failed class's name. + if (Registered != Cls) + return make_error( + "Unable to register Objective-C class"); + } + return Error::success(); + }); } Error MachOPlatformRuntimeState::registerSwift5Protocols(JITDylibState &JDS) { - if (JDS.Swift5ProtocolsSectionsNew.empty()) + if (!JDS.Swift5ProtocolsSections.hasNewSections()) return Error::success(); if (ORC_RT_UNLIKELY(!swift_registerProtocols)) return make_error("swift_registerProtocols is not available"); - for (const auto &Swift5Protocols : JDS.Swift5ProtocolsSectionsNew) + JDS.Swift5ProtocolsSections.processNewSections([](span ProtoSec) { swift_registerProtocols( - reinterpret_cast(Swift5Protocols.data()), - reinterpret_cast(Swift5Protocols.data() + - Swift5Protocols.size())); + reinterpret_cast(ProtoSec.data()), + reinterpret_cast(ProtoSec.data() + + ProtoSec.size())); + }); - moveAppendSections(JDS.Swift5ProtocolsSections, - JDS.Swift5ProtocolsSectionsNew); return Error::success(); } Error MachOPlatformRuntimeState::registerSwift5ProtocolConformances( JITDylibState &JDS) { - if (JDS.Swift5ProtocolConformancesSectionsNew.empty()) + if (!JDS.Swift5ProtocolConformancesSections.hasNewSections()) return Error::success(); if (ORC_RT_UNLIKELY(!swift_registerProtocolConformances)) return make_error( "swift_registerProtocolConformances is not available"); - for (const auto &ProtoConfSec : JDS.Swift5ProtocolConformancesSectionsNew) - swift_registerProtocolConformances( - reinterpret_cast( - ProtoConfSec.data()), - reinterpret_cast( - ProtoConfSec.data() + ProtoConfSec.size())); + JDS.Swift5ProtocolConformancesSections.processNewSections( + [](span ProtoConfSec) { + swift_registerProtocolConformances( + reinterpret_cast( + ProtoConfSec.data()), + reinterpret_cast( + ProtoConfSec.data() + ProtoConfSec.size())); + }); - moveAppendSections(JDS.Swift5ProtocolConformancesSections, - JDS.Swift5ProtocolConformancesSectionsNew); return Error::success(); } Error MachOPlatformRuntimeState::registerSwift5Types(JITDylibState &JDS) { - if (JDS.Swift5TypesSectionsNew.empty()) + if (!JDS.Swift5TypesSections.hasNewSections()) return Error::success(); if (ORC_RT_UNLIKELY(!swift_registerTypeMetadataRecords)) return make_error( "swift_registerTypeMetadataRecords is not available"); - for (const auto &TypeSec : JDS.Swift5TypesSectionsNew) + JDS.Swift5TypesSections.processNewSections([&](span TypesSec) { swift_registerTypeMetadataRecords( - reinterpret_cast(TypeSec.data()), - reinterpret_cast(TypeSec.data() + - TypeSec.size())); + reinterpret_cast(TypesSec.data()), + reinterpret_cast(TypesSec.data() + + TypesSec.size())); + }); - moveAppendSections(JDS.Swift5TypesSections, JDS.Swift5TypesSectionsNew); return Error::success(); } Error MachOPlatformRuntimeState::runModInits(JITDylibState &JDS) { - - for (const auto &ModInits : JDS.ModInitsSectionsNew) { - for (void (*Init)() : ModInits) - (*Init)(); - } - - moveAppendSections(JDS.ModInitsSections, JDS.ModInitsSectionsNew); + JDS.ModInitsSections.processNewSections([](span Inits) { + for (auto *Init : Inits) + Init(); + }); return Error::success(); } @@ -891,8 +928,7 @@ Error MachOPlatformRuntimeState::dlcloseDeinitialize(JITDylibState &JDS) { runAtExits(JDS); // Reset mod-inits - moveAppendSections(JDS.ModInitsSections, JDS.ModInitsSectionsNew); - JDS.ModInitsSectionsNew = std::move(JDS.ModInitsSections); + JDS.ModInitsSections.reset(); // Reset data section contents. for (auto &KV : JDS.DataSectionContent) -- 2.7.4