Skip to content

Commit 68f31aa

Browse files
authored
[ORC][Runtime] Add dlupdate for MachO (#97441)
With the help of @lhames, This pull request introduces the `dlupdate` function in the ORC runtime. `dlupdate` enables incremental execution of new initializers introduced in the REPL environment. Unlike traditional `dlopen`, which manages initializers, code mapping, and library reference counts, `dlupdate` focuses exclusively on running new initializers.
1 parent 6e854a6 commit 68f31aa

File tree

6 files changed

+128
-2
lines changed

6 files changed

+128
-2
lines changed

compiler-rt/lib/orc/dlfcn_wrapper.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ using namespace orc_rt;
2020

2121
extern "C" const char *__orc_rt_jit_dlerror();
2222
extern "C" void *__orc_rt_jit_dlopen(const char *path, int mode);
23+
extern "C" int __orc_rt_jit_dlupdate(void *dso_handle, int mode);
2324
extern "C" int __orc_rt_jit_dlclose(void *dso_handle);
2425

2526
ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
@@ -41,6 +42,18 @@ __orc_rt_jit_dlopen_wrapper(const char *ArgData, size_t ArgSize) {
4142
.release();
4243
}
4344

45+
#ifdef __APPLE__
46+
ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
47+
__orc_rt_jit_dlupdate_wrapper(const char *ArgData, size_t ArgSize) {
48+
return WrapperFunction<int32_t(SPSExecutorAddr, int32_t)>::handle(
49+
ArgData, ArgSize,
50+
[](ExecutorAddr &DSOHandle, int32_t mode) {
51+
return __orc_rt_jit_dlupdate(DSOHandle.toPtr<void *>(), mode);
52+
})
53+
.release();
54+
}
55+
#endif
56+
4457
ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
4558
__orc_rt_jit_dlclose_wrapper(const char *ArgData, size_t ArgSize) {
4659
return WrapperFunction<int32_t(SPSExecutorAddr)>::handle(

compiler-rt/lib/orc/macho_platform.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ class MachOPlatformRuntimeState {
331331

332332
const char *dlerror();
333333
void *dlopen(std::string_view Name, int Mode);
334+
int dlupdate(void *DSOHandle, int Mode);
334335
int dlclose(void *DSOHandle);
335336
void *dlsym(void *DSOHandle, const char *Symbol);
336337

@@ -380,6 +381,12 @@ class MachOPlatformRuntimeState {
380381
Error dlopenInitialize(std::unique_lock<std::mutex> &JDStatesLock,
381382
JITDylibState &JDS, MachOJITDylibDepInfoMap &DepInfo);
382383

384+
Error dlupdateImpl(void *DSOHandle, int Mode);
385+
Error dlupdateFull(std::unique_lock<std::mutex> &JDStatesLock,
386+
JITDylibState &JDS);
387+
Error dlupdateInitialize(std::unique_lock<std::mutex> &JDStatesLock,
388+
JITDylibState &JDS);
389+
383390
Error dlcloseImpl(void *DSOHandle);
384391
Error dlcloseDeinitialize(std::unique_lock<std::mutex> &JDStatesLock,
385392
JITDylibState &JDS);
@@ -789,6 +796,20 @@ void *MachOPlatformRuntimeState::dlopen(std::string_view Path, int Mode) {
789796
}
790797
}
791798

799+
int MachOPlatformRuntimeState::dlupdate(void *DSOHandle, int Mode) {
800+
ORC_RT_DEBUG({
801+
std::string S;
802+
printdbg("MachOPlatform::dlupdate(%p) (%s)\n", DSOHandle, S.c_str());
803+
});
804+
std::lock_guard<std::recursive_mutex> Lock(DyldAPIMutex);
805+
if (auto Err = dlupdateImpl(DSOHandle, Mode)) {
806+
// FIXME: Make dlerror thread safe.
807+
DLFcnError = toString(std::move(Err));
808+
return -1;
809+
}
810+
return 0;
811+
}
812+
792813
int MachOPlatformRuntimeState::dlclose(void *DSOHandle) {
793814
ORC_RT_DEBUG({
794815
auto *JDS = getJITDylibStateByHeader(DSOHandle);
@@ -1244,6 +1265,67 @@ Error MachOPlatformRuntimeState::dlopenInitialize(
12441265
return Error::success();
12451266
}
12461267

1268+
Error MachOPlatformRuntimeState::dlupdateImpl(void *DSOHandle, int Mode) {
1269+
std::unique_lock<std::mutex> Lock(JDStatesMutex);
1270+
1271+
// Try to find JITDylib state by DSOHandle.
1272+
auto *JDS = getJITDylibStateByHeader(DSOHandle);
1273+
1274+
if (!JDS) {
1275+
std::ostringstream ErrStream;
1276+
ErrStream << "No registered JITDylib for " << DSOHandle;
1277+
return make_error<StringError>(ErrStream.str());
1278+
}
1279+
1280+
if (!JDS->referenced())
1281+
return make_error<StringError>("dlupdate failed, JITDylib must be open.");
1282+
1283+
if (!JDS->Sealed) {
1284+
if (auto Err = dlupdateFull(Lock, *JDS))
1285+
return Err;
1286+
}
1287+
1288+
return Error::success();
1289+
}
1290+
1291+
Error MachOPlatformRuntimeState::dlupdateFull(
1292+
std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
1293+
// Call back to the JIT to push the initializers.
1294+
Expected<MachOJITDylibDepInfoMap> DepInfo((MachOJITDylibDepInfoMap()));
1295+
// Unlock so that we can accept the initializer update.
1296+
JDStatesLock.unlock();
1297+
if (auto Err = WrapperFunction<SPSExpected<SPSMachOJITDylibDepInfoMap>(
1298+
SPSExecutorAddr)>::
1299+
call(JITDispatch(&__orc_rt_macho_push_initializers_tag), DepInfo,
1300+
ExecutorAddr::fromPtr(JDS.Header)))
1301+
return Err;
1302+
JDStatesLock.lock();
1303+
1304+
if (!DepInfo)
1305+
return DepInfo.takeError();
1306+
1307+
if (auto Err = dlupdateInitialize(JDStatesLock, JDS))
1308+
return Err;
1309+
1310+
return Error::success();
1311+
}
1312+
1313+
Error MachOPlatformRuntimeState::dlupdateInitialize(
1314+
std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
1315+
ORC_RT_DEBUG({
1316+
printdbg("MachOPlatformRuntimeState::dlupdateInitialize(\"%s\")\n",
1317+
JDS.Name.c_str());
1318+
});
1319+
1320+
// Initialize this JITDylib.
1321+
if (auto Err = registerObjCRegistrationObjects(JDStatesLock, JDS))
1322+
return Err;
1323+
if (auto Err = runModInits(JDStatesLock, JDS))
1324+
return Err;
1325+
1326+
return Error::success();
1327+
}
1328+
12471329
Error MachOPlatformRuntimeState::dlcloseImpl(void *DSOHandle) {
12481330
std::unique_lock<std::mutex> Lock(JDStatesMutex);
12491331

@@ -1517,6 +1599,10 @@ void *__orc_rt_macho_jit_dlopen(const char *path, int mode) {
15171599
return MachOPlatformRuntimeState::get().dlopen(path, mode);
15181600
}
15191601

1602+
int __orc_rt_macho_jit_dlupdate(void *dso_handle, int mode) {
1603+
return MachOPlatformRuntimeState::get().dlupdate(dso_handle, mode);
1604+
}
1605+
15201606
int __orc_rt_macho_jit_dlclose(void *dso_handle) {
15211607
return MachOPlatformRuntimeState::get().dlclose(dso_handle);
15221608
}

compiler-rt/lib/orc/macho_platform.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ ORC_RT_INTERFACE void __orc_rt_macho_cxa_finalize(void *dso_handle);
2424
// dlfcn functions.
2525
ORC_RT_INTERFACE const char *__orc_rt_macho_jit_dlerror();
2626
ORC_RT_INTERFACE void *__orc_rt_macho_jit_dlopen(const char *path, int mode);
27+
ORC_RT_INTERFACE int __orc_rt_macho_jit_dlupdate(void *dso_handle, int mode);
2728
ORC_RT_INTERFACE int __orc_rt_macho_jit_dlclose(void *dso_handle);
2829
ORC_RT_INTERFACE void *__orc_rt_macho_jit_dlsym(void *dso_handle,
2930
const char *symbol);

llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef LLVM_EXECUTIONENGINE_ORC_LLJIT_H
1414
#define LLVM_EXECUTIONENGINE_ORC_LLJIT_H
1515

16+
#include "llvm/ADT/SmallSet.h"
1617
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
1718
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
1819
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
@@ -620,6 +621,7 @@ class ORCPlatformSupport : public LLJIT::PlatformSupport {
620621
private:
621622
orc::LLJIT &J;
622623
DenseMap<orc::JITDylib *, orc::ExecutorAddr> DSOHandles;
624+
SmallPtrSet<JITDylib const *, 8> InitializedDylib;
623625
};
624626

625627
} // End namespace orc

llvm/lib/ExecutionEngine/Orc/LLJIT.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,7 @@ Error ORCPlatformSupport::initialize(orc::JITDylib &JD) {
602602
using llvm::orc::shared::SPSExecutorAddr;
603603
using llvm::orc::shared::SPSString;
604604
using SPSDLOpenSig = SPSExecutorAddr(SPSString, int32_t);
605+
using SPSDLUpdateSig = int32_t(SPSExecutorAddr, int32_t);
605606
enum dlopen_mode : int32_t {
606607
ORC_RT_RTLD_LAZY = 0x1,
607608
ORC_RT_RTLD_NOW = 0x2,
@@ -612,9 +613,30 @@ Error ORCPlatformSupport::initialize(orc::JITDylib &JD) {
612613
auto &ES = J.getExecutionSession();
613614
auto MainSearchOrder = J.getMainJITDylib().withLinkOrderDo(
614615
[](const JITDylibSearchOrder &SO) { return SO; });
616+
StringRef WrapperToCall = "__orc_rt_jit_dlopen_wrapper";
617+
bool dlupdate = false;
618+
if (ES.getTargetTriple().isOSBinFormatMachO()) {
619+
if (InitializedDylib.contains(&JD)) {
620+
WrapperToCall = "__orc_rt_jit_dlupdate_wrapper";
621+
dlupdate = true;
622+
} else
623+
InitializedDylib.insert(&JD);
624+
}
615625

616-
if (auto WrapperAddr = ES.lookup(
617-
MainSearchOrder, J.mangleAndIntern("__orc_rt_jit_dlopen_wrapper"))) {
626+
if (auto WrapperAddr =
627+
ES.lookup(MainSearchOrder, J.mangleAndIntern(WrapperToCall))) {
628+
if (dlupdate) {
629+
int32_t result;
630+
auto E = ES.callSPSWrapper<SPSDLUpdateSig>(WrapperAddr->getAddress(),
631+
result, DSOHandles[&JD],
632+
int32_t(ORC_RT_RTLD_LAZY));
633+
if (E)
634+
return E;
635+
else if (result)
636+
return make_error<StringError>("dlupdate failed",
637+
inconvertibleErrorCode());
638+
return Error::success();
639+
}
618640
return ES.callSPSWrapper<SPSDLOpenSig>(WrapperAddr->getAddress(),
619641
DSOHandles[&JD], JD.getName(),
620642
int32_t(ORC_RT_RTLD_LAZY));
@@ -641,6 +663,7 @@ Error ORCPlatformSupport::deinitialize(orc::JITDylib &JD) {
641663
return make_error<StringError>("dlclose failed",
642664
inconvertibleErrorCode());
643665
DSOHandles.erase(&JD);
666+
InitializedDylib.erase(&JD);
644667
} else
645668
return WrapperAddr.takeError();
646669
return Error::success();

llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ MachOPlatform::standardRuntimeUtilityAliases() {
428428
{"___orc_rt_run_program", "___orc_rt_macho_run_program"},
429429
{"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"},
430430
{"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"},
431+
{"___orc_rt_jit_dlupdate", "___orc_rt_macho_jit_dlupdate"},
431432
{"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"},
432433
{"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"},
433434
{"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};

0 commit comments

Comments
 (0)