Skip to content

Commit 781feaa

Browse files
committed
Implement heuristic to prioritize in field descriptor search
Currently when looking for field descriptors we parse the reflection metadata in whatever order it was registered. This patch implements a heuristic where we try to match a new optional Name field with the module name of the type's field descriptor we're looking for. rdar://87889973
1 parent 0597b8d commit 781feaa

File tree

4 files changed

+142
-78
lines changed

4 files changed

+142
-78
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 59 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,9 @@ class ReflectionContext
227227
return sizeof(StoredPointer) * 2;
228228
}
229229

230-
template <typename T> bool readMachOSections(RemoteAddress ImageStart) {
230+
template <typename T>
231+
bool readMachOSections(RemoteAddress ImageStart,
232+
llvm::Optional<llvm::StringRef> Name = llvm::None) {
231233
auto Buf =
232234
this->getReader().readBytes(ImageStart, sizeof(typename T::Header));
233235
if (!Buf)
@@ -337,15 +339,15 @@ class ReflectionContext
337339
MPEnumMdSec.first == nullptr)
338340
return false;
339341

340-
ReflectionInfo info = {
341-
{FieldMdSec.first, FieldMdSec.second},
342-
{AssocTySec.first, AssocTySec.second},
343-
{BuiltinTySec.first, BuiltinTySec.second},
344-
{CaptureSec.first, CaptureSec.second},
345-
{TypeRefMdSec.first, TypeRefMdSec.second},
346-
{ReflStrMdSec.first, ReflStrMdSec.second},
347-
{ConformMdSec.first, ConformMdSec.second},
348-
{MPEnumMdSec.first, MPEnumMdSec.second}};
342+
ReflectionInfo info = {{FieldMdSec.first, FieldMdSec.second},
343+
{AssocTySec.first, AssocTySec.second},
344+
{BuiltinTySec.first, BuiltinTySec.second},
345+
{CaptureSec.first, CaptureSec.second},
346+
{TypeRefMdSec.first, TypeRefMdSec.second},
347+
{ReflStrMdSec.first, ReflStrMdSec.second},
348+
{ConformMdSec.first, ConformMdSec.second},
349+
{MPEnumMdSec.first, MPEnumMdSec.second},
350+
Name};
349351

350352
this->addReflectionInfo(info);
351353

@@ -374,7 +376,8 @@ class ReflectionContext
374376
return true;
375377
}
376378

377-
bool readPECOFFSections(RemoteAddress ImageStart) {
379+
bool readPECOFFSections(RemoteAddress ImageStart,
380+
llvm::Optional<llvm::StringRef> Name = llvm::None) {
378381
auto DOSHdrBuf = this->getReader().readBytes(
379382
ImageStart, sizeof(llvm::object::dos_header));
380383
if (!DOSHdrBuf)
@@ -463,20 +466,21 @@ class ReflectionContext
463466
MPEnumMdSec.first == nullptr)
464467
return false;
465468

466-
ReflectionInfo Info = {
467-
{FieldMdSec.first, FieldMdSec.second},
468-
{AssocTySec.first, AssocTySec.second},
469-
{BuiltinTySec.first, BuiltinTySec.second},
470-
{CaptureSec.first, CaptureSec.second},
471-
{TypeRefMdSec.first, TypeRefMdSec.second},
472-
{ReflStrMdSec.first, ReflStrMdSec.second},
473-
{ConformMdSec.first, ConformMdSec.second},
474-
{MPEnumMdSec.first, MPEnumMdSec.second}};
469+
ReflectionInfo Info = {{FieldMdSec.first, FieldMdSec.second},
470+
{AssocTySec.first, AssocTySec.second},
471+
{BuiltinTySec.first, BuiltinTySec.second},
472+
{CaptureSec.first, CaptureSec.second},
473+
{TypeRefMdSec.first, TypeRefMdSec.second},
474+
{ReflStrMdSec.first, ReflStrMdSec.second},
475+
{ConformMdSec.first, ConformMdSec.second},
476+
{MPEnumMdSec.first, MPEnumMdSec.second},
477+
Name};
475478
this->addReflectionInfo(Info);
476479
return true;
477480
}
478481

479-
bool readPECOFF(RemoteAddress ImageStart) {
482+
bool readPECOFF(RemoteAddress ImageStart,
483+
llvm::Optional<llvm::StringRef> Name = llvm::None) {
480484
auto Buf = this->getReader().readBytes(ImageStart,
481485
sizeof(llvm::object::dos_header));
482486
if (!Buf)
@@ -495,12 +499,13 @@ class ReflectionContext
495499
if (memcmp(Buf.get(), llvm::COFF::PEMagic, sizeof(llvm::COFF::PEMagic)))
496500
return false;
497501

498-
return readPECOFFSections(ImageStart);
502+
return readPECOFFSections(ImageStart, Name);
499503
}
500504

501505
template <typename T>
502506
bool readELFSections(RemoteAddress ImageStart,
503-
llvm::Optional<llvm::sys::MemoryBlock> FileBuffer) {
507+
llvm::Optional<llvm::sys::MemoryBlock> FileBuffer,
508+
llvm::Optional<llvm::StringRef> Name = llvm::None) {
504509
// When reading from the FileBuffer we can simply return a pointer to
505510
// the underlying data.
506511
// When reading from the process, we need to keep the memory around
@@ -655,15 +660,15 @@ class ReflectionContext
655660
MPEnumMdSec.first == nullptr)
656661
return false;
657662

658-
ReflectionInfo info = {
659-
{FieldMdSec.first, FieldMdSec.second},
660-
{AssocTySec.first, AssocTySec.second},
661-
{BuiltinTySec.first, BuiltinTySec.second},
662-
{CaptureSec.first, CaptureSec.second},
663-
{TypeRefMdSec.first, TypeRefMdSec.second},
664-
{ReflStrMdSec.first, ReflStrMdSec.second},
665-
{ConformMdSec.first, ConformMdSec.second},
666-
{MPEnumMdSec.first, MPEnumMdSec.second}};
663+
ReflectionInfo info = {{FieldMdSec.first, FieldMdSec.second},
664+
{AssocTySec.first, AssocTySec.second},
665+
{BuiltinTySec.first, BuiltinTySec.second},
666+
{CaptureSec.first, CaptureSec.second},
667+
{TypeRefMdSec.first, TypeRefMdSec.second},
668+
{ReflStrMdSec.first, ReflStrMdSec.second},
669+
{ConformMdSec.first, ConformMdSec.second},
670+
{MPEnumMdSec.first, MPEnumMdSec.second},
671+
Name};
667672

668673
this->addReflectionInfo(info);
669674
return true;
@@ -687,7 +692,9 @@ class ReflectionContext
687692
/// \return
688693
/// /b True if the metadata information was parsed successfully,
689694
/// /b false otherwise.
690-
bool readELF(RemoteAddress ImageStart, llvm::Optional<llvm::sys::MemoryBlock> FileBuffer) {
695+
bool readELF(RemoteAddress ImageStart,
696+
llvm::Optional<llvm::sys::MemoryBlock> FileBuffer,
697+
llvm::Optional<llvm::StringRef> Name = llvm::None) {
691698
auto Buf =
692699
this->getReader().readBytes(ImageStart, sizeof(llvm::ELF::Elf64_Ehdr));
693700
if (!Buf)
@@ -703,16 +710,16 @@ class ReflectionContext
703710
unsigned char FileClass = Hdr->getFileClass();
704711
if (FileClass == llvm::ELF::ELFCLASS64) {
705712
return readELFSections<ELFTraits<llvm::ELF::ELFCLASS64>>(
706-
ImageStart, FileBuffer);
713+
ImageStart, FileBuffer, Name);
707714
} else if (FileClass == llvm::ELF::ELFCLASS32) {
708715
return readELFSections<ELFTraits<llvm::ELF::ELFCLASS32>>(
709-
ImageStart, FileBuffer);
716+
ImageStart, FileBuffer, Name);
710717
} else {
711718
return false;
712719
}
713720
}
714721

715-
bool addImage(RemoteAddress ImageStart) {
722+
bool addImage(RemoteAddress ImageStart, llvm::Optional<llvm::StringRef> Name = llvm::None) {
716723
// Read the first few bytes to look for a magic header.
717724
auto Magic = this->getReader().readBytes(ImageStart, sizeof(uint32_t));
718725
if (!Magic)
@@ -723,18 +730,18 @@ class ReflectionContext
723730

724731
// 32- and 64-bit Mach-O.
725732
if (MagicWord == llvm::MachO::MH_MAGIC) {
726-
return readMachOSections<MachOTraits<4>>(ImageStart);
733+
return readMachOSections<MachOTraits<4>>(ImageStart, Name);
727734
}
728735

729736
if (MagicWord == llvm::MachO::MH_MAGIC_64) {
730-
return readMachOSections<MachOTraits<8>>(ImageStart);
737+
return readMachOSections<MachOTraits<8>>(ImageStart, Name);
731738
}
732739

733740
// PE. (This just checks for the DOS header; `readPECOFF` will further
734741
// validate the existence of the PE header.)
735742
auto MagicBytes = (const char*)Magic.get();
736743
if (MagicBytes[0] == 'M' && MagicBytes[1] == 'Z') {
737-
return readPECOFF(ImageStart);
744+
return readPECOFF(ImageStart, Name);
738745
}
739746

740747

@@ -743,7 +750,7 @@ class ReflectionContext
743750
&& MagicBytes[1] == llvm::ELF::ElfMagic[1]
744751
&& MagicBytes[2] == llvm::ELF::ElfMagic[2]
745752
&& MagicBytes[3] == llvm::ELF::ElfMagic[3]) {
746-
return readELF(ImageStart, llvm::Optional<llvm::sys::MemoryBlock>());
753+
return readELF(ImageStart, llvm::Optional<llvm::sys::MemoryBlock>(), Name);
747754
}
748755

749756
// We don't recognize the format.
@@ -759,8 +766,9 @@ class ReflectionContext
759766
/// \b True if any of the reflection sections were registered,
760767
/// \b false otherwise.
761768
bool addImage(llvm::function_ref<
762-
std::pair<RemoteRef<void>, uint64_t>(ReflectionSectionKind)>
763-
FindSection) {
769+
std::pair<RemoteRef<void>, uint64_t>(ReflectionSectionKind)>
770+
FindSection,
771+
llvm::Optional<llvm::StringRef> Name) {
764772
auto Sections = {
765773
ReflectionSectionKind::fieldmd, ReflectionSectionKind::assocty,
766774
ReflectionSectionKind::builtin, ReflectionSectionKind::capture,
@@ -784,11 +792,15 @@ class ReflectionContext
784792
if (llvm::all_of(Pairs, [](const auto &Pair) { return !Pair.first; }))
785793
return false;
786794

787-
ReflectionInfo Info = {
788-
{Pairs[0].first, Pairs[0].second}, {Pairs[1].first, Pairs[1].second},
789-
{Pairs[2].first, Pairs[2].second}, {Pairs[3].first, Pairs[3].second},
790-
{Pairs[4].first, Pairs[4].second}, {Pairs[5].first, Pairs[5].second},
791-
{Pairs[6].first, Pairs[6].second}, {Pairs[7].first, Pairs[7].second}};
795+
ReflectionInfo Info = {{Pairs[0].first, Pairs[0].second},
796+
{Pairs[1].first, Pairs[1].second},
797+
{Pairs[2].first, Pairs[2].second},
798+
{Pairs[3].first, Pairs[3].second},
799+
{Pairs[4].first, Pairs[4].second},
800+
{Pairs[5].first, Pairs[5].second},
801+
{Pairs[6].first, Pairs[6].second},
802+
{Pairs[7].first, Pairs[7].second},
803+
Name};
792804
this->addReflectionInfo(Info);
793805
return true;
794806
}

include/swift/Reflection/TypeRefBuilder.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <ostream>
3030
#include <sstream>
3131
#include <unordered_map>
32+
#include <unordered_set>
3233
#include <vector>
3334

3435
namespace swift {
@@ -264,6 +265,7 @@ struct ReflectionInfo {
264265
GenericSection ReflectionString;
265266
GenericSection Conformance;
266267
MultiPayloadEnumSection MultiPayloadEnum;
268+
llvm::Optional<llvm::StringRef> Name;
267269
};
268270

269271
struct ClosureContextInfo {
@@ -827,10 +829,9 @@ class TypeRefBuilder {
827829
private:
828830
std::vector<ReflectionInfo> ReflectionInfos;
829831

830-
/// Index of the next Reflection Info that should be processed.
831-
/// This assumes that Reflection Infos are never removed from the vector.
832-
size_t FirstUnprocessedReflectionInfoIndex = 0;
833-
832+
/// Reflection Infos we've already processed.
833+
std::unordered_set<const ReflectionInfo *> ProcessedReflectionInfos;
834+
834835
llvm::Optional<std::string> normalizeReflectionName(RemoteRef<char> name);
835836
bool reflectionNameMatches(RemoteRef<char> reflectionName,
836837
StringRef searchName);
@@ -1548,7 +1549,7 @@ class TypeRefBuilder {
15481549
mangledTypeName};
15491550
}
15501551
};
1551-
1552+
void PopulateFieldTypeInfoCacheWithReflectionInfo(ReflectionInfo &Info);
15521553
public:
15531554
template <template <typename Runtime> class ObjCInteropKind,
15541555
unsigned PointerSize>

stdlib/public/Reflection/TypeRefBuilder.cpp

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -193,36 +193,85 @@ const TypeRef *TypeRefBuilder::lookupSuperclass(const TypeRef *TR) {
193193
return Unsubstituted->subst(*this, *SubstMap);
194194
}
195195

196+
static llvm::Optional<StringRef> FindOutermostModuleName(NodePointer Node) {
197+
// Breadth first search until we find the module name so we find the outermost
198+
// one.
199+
llvm::SmallVector<NodePointer, 8> Queue;
200+
Queue.push_back(Node);
201+
// Instead of removing items from the front of the queue we just iterate over
202+
// them.
203+
for (size_t i = 0; i < Queue.size(); ++i) {
204+
NodePointer Current = Queue[i];
205+
if (Current->getKind() == Node::Kind::Module) {
206+
if (Current->hasText())
207+
return Current->getText();
208+
else
209+
return {};
210+
}
211+
for (auto Child : *Current)
212+
Queue.push_back(Child);
213+
}
214+
return {};
215+
}
216+
217+
void TypeRefBuilder::PopulateFieldTypeInfoCacheWithReflectionInfo(
218+
ReflectionInfo &Info) {
219+
if (ProcessedReflectionInfos.find(&Info) != ProcessedReflectionInfos.end())
220+
return;
221+
222+
for (auto FD : Info.Field) {
223+
if (!FD->hasMangledTypeName())
224+
continue;
225+
auto CandidateMangledName = readTypeRef(FD, FD->MangledTypeName);
226+
if (auto NormalizedName = normalizeReflectionName(CandidateMangledName)) {
227+
FieldTypeInfoCache[std::move(*NormalizedName)] = FD;
228+
}
229+
}
230+
231+
ProcessedReflectionInfos.emplace(&Info);
232+
}
233+
196234
RemoteRef<FieldDescriptor>
197235
TypeRefBuilder::getFieldTypeInfo(const TypeRef *TR) {
198236
const std::string *MangledName;
199-
if (auto N = dyn_cast<NominalTypeRef>(TR))
237+
NodePointer Node;
238+
Demangler Dem;
239+
if (auto N = dyn_cast<NominalTypeRef>(TR)) {
240+
Node = N->getDemangling(Dem);
200241
MangledName = &N->getMangledName();
201-
else if (auto BG = dyn_cast<BoundGenericTypeRef>(TR))
242+
} else if (auto BG = dyn_cast<BoundGenericTypeRef>(TR)) {
243+
Node = BG->getDemangling(Dem);
202244
MangledName = &BG->getMangledName();
245+
}
203246
else
204247
return nullptr;
205248

206249
// Try the cache.
207250
auto Found = FieldTypeInfoCache.find(*MangledName);
208251
if (Found != FieldTypeInfoCache.end())
209252
return Found->second;
253+
254+
// Heuristic: find the outermost Module node available, and try to parse the
255+
// ReflectionInfos with a matching name first.
256+
auto ModuleName = FindOutermostModuleName(Node);
257+
// If we couldn't find a module name or the type is imported (__C module) we
258+
// don't any useful information on which image to look for the type.
259+
if (ModuleName && ModuleName != llvm::StringRef("__C")) {
260+
for (auto &Info : ReflectionInfos) {
261+
if (ModuleName == Info.Name) {
262+
PopulateFieldTypeInfoCacheWithReflectionInfo(Info);
263+
Found = FieldTypeInfoCache.find(*MangledName);
264+
if (Found != FieldTypeInfoCache.end()) {
265+
return Found->second;
266+
}
267+
}
268+
}
269+
}
210270

211271
// On failure, fill out the cache, ReflectionInfo by ReflectionInfo,
212272
// until we find the field descriptor we're looking for.
213-
while (FirstUnprocessedReflectionInfoIndex < ReflectionInfos.size()) {
214-
auto &Info = ReflectionInfos[FirstUnprocessedReflectionInfoIndex];
215-
for (auto FD : Info.Field) {
216-
if (!FD->hasMangledTypeName())
217-
continue;
218-
auto CandidateMangledName = readTypeRef(FD, FD->MangledTypeName);
219-
if (auto NormalizedName = normalizeReflectionName(CandidateMangledName))
220-
FieldTypeInfoCache[std::move(*NormalizedName)] = FD;
221-
}
222-
223-
// Since we're done with the current ReflectionInfo, increment early in
224-
// case we get a cache hit.
225-
++FirstUnprocessedReflectionInfoIndex;
273+
for (auto &Info : ReflectionInfos) {
274+
PopulateFieldTypeInfoCacheWithReflectionInfo(Info);
226275
Found = FieldTypeInfoCache.find(*MangledName);
227276
if (Found != FieldTypeInfoCache.end())
228277
return Found->second;

stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,15 @@ swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef,
238238
}
239239

240240
ReflectionInfo ContextInfo{
241-
sectionFromInfo<FieldDescriptorIterator>(Info, Info.field),
242-
sectionFromInfo<AssociatedTypeIterator>(Info, Info.associated_types),
243-
sectionFromInfo<BuiltinTypeDescriptorIterator>(Info, Info.builtin_types),
244-
sectionFromInfo<CaptureDescriptorIterator>(Info, Info.capture),
245-
sectionFromInfo<const void *>(Info, Info.type_references),
246-
sectionFromInfo<const void *>(Info, Info.reflection_strings),
247-
ReflectionSection<const void *>(nullptr, 0),
248-
ReflectionSection<MultiPayloadEnumDescriptorIterator>(0, 0)};
241+
sectionFromInfo<FieldDescriptorIterator>(Info, Info.field),
242+
sectionFromInfo<AssociatedTypeIterator>(Info, Info.associated_types),
243+
sectionFromInfo<BuiltinTypeDescriptorIterator>(Info, Info.builtin_types),
244+
sectionFromInfo<CaptureDescriptorIterator>(Info, Info.capture),
245+
sectionFromInfo<const void *>(Info, Info.type_references),
246+
sectionFromInfo<const void *>(Info, Info.reflection_strings),
247+
ReflectionSection<const void *>(nullptr, 0),
248+
ReflectionSection<MultiPayloadEnumDescriptorIterator>(0, 0),
249+
llvm::None};
249250

250251
Context->addReflectionInfo(ContextInfo);
251252
}
@@ -264,10 +265,11 @@ void swift_reflection_addReflectionMappingInfo(
264265
reflectionSectionFromLocalAndRemote<CaptureDescriptorIterator>(
265266
Info.capture),
266267
reflectionSectionFromLocalAndRemote<const void *>(Info.type_references),
267-
reflectionSectionFromLocalAndRemote<const void *>(Info.reflection_strings),
268+
reflectionSectionFromLocalAndRemote<const void *>(
269+
Info.reflection_strings),
268270
ReflectionSection<const void *>(nullptr, 0),
269-
MultiPayloadEnumSection(0, 0)
270-
};
271+
MultiPayloadEnumSection(0, 0),
272+
llvm::None};
271273

272274
Context->addReflectionInfo(ContextInfo);
273275
}

0 commit comments

Comments
 (0)