Skip to content

Commit 437b4f1

Browse files
committed
[ORC-RT][ORC][MachO] Refactor dlsym to extract a reusable bulk-lookup API.
MachOPlatformRuntimeState::lookupSymbols encapsulates the approach used in dlsym in bb41fc6, but generalizes it to multiple symbols: 1. try to resolve symbols locally 2. issue a push-request for any unresolved symbols 3. re-try local resolution In the future lookupSymbols can serve as the basis for a public bulk lookup API in the ORC runtime.
1 parent 8615ead commit 437b4f1

File tree

1 file changed

+69
-72
lines changed

1 file changed

+69
-72
lines changed

compiler-rt/lib/orc/macho_platform.cpp

Lines changed: 69 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -352,36 +352,13 @@ class MachOPlatformRuntimeState {
352352
Error requestPushSymbols(JITDylibState &JDS,
353353
span<std::pair<std::string_view, bool>> Symbols);
354354

355-
/// Visits the symbol table for the JITDylib associated with DSOHandle.
356-
/// Visitor should be callable as
357-
///
358-
/// void (size_t,
359-
/// std::optional<std::pair<ExecutorAddr, MachOExecutorSymbolFlags>>)
360-
///
361-
/// The visitor function will be called for each element of the Symbols, but
362-
/// in an arbitrary order. The first argument of the callback will indicate
363-
/// the index of the result. The second argument will be std::nullopt (if the
364-
/// symbol at the given index was not present in the symbol table), or a
365-
/// pair containing the symbol's address and flags.
366-
///
367-
/// This function will remove all elements of Symbols that are found, leaving
368-
/// only the symbols that were not. This allows it to dovetail with
369-
/// requestPushSymbols, enabling the following idiom:
370-
///
371-
/// ...
372-
/// visitSymbolAddrs(DSO, Symbols);
373-
/// if (!Symbols.empty()) {
374-
/// requestPushSymbols(DSO, Symbols);
375-
/// visitSymbolAddrs(DSO, Symbols);
376-
/// for (auto &Sym : Symbols) {
377-
/// -- handle symbols that were not found --
378-
/// }
379-
/// }
380-
///
381-
template <typename VisitorFn>
382-
void visitSymbolAddrs(JITDylibState &JDS,
383-
std::vector<std::pair<std::string_view, bool>> &Symbols,
384-
VisitorFn &&Visit);
355+
/// Attempts to look up the given symbols locally, requesting a push from the
356+
/// remote if they're not found. Results are written to the Result span, which
357+
/// must have the same size as the Symbols span.
358+
Error
359+
lookupSymbols(JITDylibState &JDS, std::unique_lock<std::mutex> &JDStatesLock,
360+
span<std::pair<ExecutorAddr, MachOExecutorSymbolFlags>> Result,
361+
span<std::pair<std::string_view, bool>> Symbols);
385362

386363
bool lookupUnwindSections(void *Addr, unw_dynamic_unwind_sections &Info);
387364

@@ -839,43 +816,16 @@ void *MachOPlatformRuntimeState::dlsym(void *DSOHandle, const char *Symbol) {
839816
return nullptr;
840817
}
841818

842-
std::string MangledName("_");
843-
MangledName += Symbol;
844-
std::vector<std::pair<std::string_view, bool>> Symbols;
845-
Symbols.push_back({MangledName, false});
819+
std::string MangledName = std::string("_") + Symbol;
820+
std::pair<std::string_view, bool> Lookup(MangledName, false);
821+
std::pair<ExecutorAddr, MachOExecutorSymbolFlags> Result;
846822

847-
ExecutorAddr Result;
848-
using ElemResult =
849-
std::optional<std::pair<ExecutorAddr, MachOExecutorSymbolFlags>>;
850-
851-
// Try to resolve the symbol in the local symbol tables.
852-
visitSymbolAddrs(*JDS, Symbols, [&](size_t Idx, ElemResult E) {
853-
if (E)
854-
Result = E->first;
855-
});
856-
857-
// Return early if we found it.
858-
if (Symbols.empty())
859-
return Result.toPtr<void *>();
860-
861-
// Otherwise call back to the controller to try to request that the symbol
862-
// be materialized.
863-
Lock.unlock();
864-
if (auto Err = requestPushSymbols(*JDS, {Symbols.data(), Symbols.size()})) {
823+
if (auto Err = lookupSymbols(*JDS, Lock, {&Result, 1}, {&Lookup, 1})) {
865824
DLFcnError = toString(std::move(Err));
866825
return nullptr;
867826
}
868-
Lock.lock();
869-
870-
// Try another local resolution.
871-
visitSymbolAddrs(*JDS, Symbols, [&](size_t Idx, ElemResult E) {
872-
if (E)
873-
Result = E->first;
874-
});
875827

876-
// At this point Result has either been set (if we found the symbol) or is
877-
// still null (if we didn't). Either way it's the right value.
878-
return Result.toPtr<void *>();
828+
return Result.first.toPtr<void *>();
879829
}
880830

881831
int MachOPlatformRuntimeState::registerAtExit(void (*F)(void *), void *Arg,
@@ -967,22 +917,69 @@ Error MachOPlatformRuntimeState::requestPushSymbols(
967917
return OpErr;
968918
}
969919

970-
template <typename VisitorFn>
971-
void MachOPlatformRuntimeState::visitSymbolAddrs(
972-
JITDylibState &JDS, std::vector<std::pair<std::string_view, bool>> &Symbols,
973-
VisitorFn &&Visit) {
974-
975-
std::vector<std::pair<std::string_view, bool>> RemainingSymbols;
976-
920+
Error MachOPlatformRuntimeState::lookupSymbols(
921+
JITDylibState &JDS, std::unique_lock<std::mutex> &JDStatesLock,
922+
span<std::pair<ExecutorAddr, MachOExecutorSymbolFlags>> Result,
923+
span<std::pair<std::string_view, bool>> Symbols) {
924+
assert(JDStatesLock.owns_lock() &&
925+
"JDStatesLock should be locked at call-site");
926+
assert(Result.size() == Symbols.size() &&
927+
"Results and Symbols span sizes should match");
928+
929+
// Make an initial pass over the local symbol table.
930+
std::vector<size_t> MissingSymbolIndexes;
977931
for (size_t Idx = 0; Idx != Symbols.size(); ++Idx) {
978932
auto I = JDS.SymbolTable.find(Symbols[Idx].first);
979933
if (I != JDS.SymbolTable.end())
980-
Visit(Idx, I->second);
934+
Result[Idx] = I->second;
981935
else
982-
RemainingSymbols.push_back(Symbols[Idx]);
936+
MissingSymbolIndexes.push_back(Idx);
983937
}
984938

985-
Symbols = std::move(RemainingSymbols);
939+
// If everything has been resolved already then bail out early.
940+
if (MissingSymbolIndexes.empty())
941+
return Error::success();
942+
943+
// Otherwise call back to the controller to try to request that the symbol
944+
// be materialized.
945+
std::vector<std::pair<std::string_view, bool>> MissingSymbols;
946+
MissingSymbols.reserve(MissingSymbolIndexes.size());
947+
printdbg("requesting push of %i missing symbols...\n",
948+
MissingSymbolIndexes.size());
949+
for (auto MissingIdx : MissingSymbolIndexes)
950+
MissingSymbols.push_back(Symbols[MissingIdx]);
951+
952+
JDStatesLock.unlock();
953+
if (auto Err = requestPushSymbols(
954+
JDS, {MissingSymbols.data(), MissingSymbols.size()}))
955+
return Err;
956+
JDStatesLock.lock();
957+
958+
// Try to resolve the previously missing symbols locally.
959+
std::vector<size_t> MissingRequiredSymbols;
960+
for (auto MissingIdx : MissingSymbolIndexes) {
961+
auto I = JDS.SymbolTable.find(Symbols[MissingIdx].first);
962+
if (I != JDS.SymbolTable.end())
963+
Result[MissingIdx] = I->second;
964+
else {
965+
if (Symbols[MissingIdx].second)
966+
MissingRequiredSymbols.push_back(MissingIdx);
967+
else
968+
Result[MissingIdx] = {ExecutorAddr(), {}};
969+
}
970+
}
971+
972+
// Error out if any missing symbols could not be resolved.
973+
if (!MissingRequiredSymbols.empty()) {
974+
std::ostringstream ErrStream;
975+
ErrStream << "Lookup could not find required symbols: [ ";
976+
for (auto MissingIdx : MissingRequiredSymbols)
977+
ErrStream << "\"" << Symbols[MissingIdx].first << "\" ";
978+
ErrStream << "]";
979+
return make_error<StringError>(ErrStream.str());
980+
}
981+
982+
return Error::success();
986983
}
987984

988985
// eh-frame registration functions.

0 commit comments

Comments
 (0)