summaryrefslogtreecommitdiff
path: root/clang/lib/Interpreter/IncrementalExecutor.cpp
diff options
context:
space:
mode:
authorMingming Liu <mingmingl@google.com>2025-09-10 15:25:31 -0700
committerGitHub <noreply@github.com>2025-09-10 15:25:31 -0700
commit1417dafa1db9cb1b2b09438aa9f53ea5ab6e36e2 (patch)
tree57f4b1f313c8cf74eed8819870f39c36ea263c68 /clang/lib/Interpreter/IncrementalExecutor.cpp
parent898b813bc8a6d0276bf0f4769f5f2f64b34e632d (diff)
parentb8cefcb601ddaa18482555c4ff363c01a270c2fe (diff)
Merge branch 'main' into users/mingmingl-llvm/samplefdo-profile-formatusers/mingmingl-llvm/samplefdo-profile-format
Diffstat (limited to 'clang/lib/Interpreter/IncrementalExecutor.cpp')
-rw-r--r--clang/lib/Interpreter/IncrementalExecutor.cpp241
1 files changed, 240 insertions, 1 deletions
diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp
index 4d2adecaafce..b0eb7d0e9f07 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.cpp
+++ b/clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -15,19 +15,36 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Interpreter/PartialTranslationUnit.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
+#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
+#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
+#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/TargetParser/Host.h"
+
+#ifdef LLVM_ON_UNIX
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#endif // LLVM_ON_UNIX
// Force linking some of the runtimes that helps attaching to a debugger.
LLVM_ATTRIBUTE_USED void linkComponents() {
@@ -55,8 +72,9 @@ IncrementalExecutor::createDefaultJITBuilder(
IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
llvm::orc::LLJITBuilder &JITBuilder,
+ Interpreter::JITConfig Config,
llvm::Error &Err)
- : TSCtx(TSC) {
+ : TSCtx(TSC), OutOfProcessChildPid(Config.ExecutorPID) {
using namespace llvm::orc;
llvm::ErrorAsOutParameter EAO(&Err);
@@ -118,4 +136,225 @@ IncrementalExecutor::getSymbolAddress(llvm::StringRef Name,
return SymOrErr->getAddress();
}
+Expected<std::unique_ptr<llvm::jitlink::JITLinkMemoryManager>>
+createSharedMemoryManager(llvm::orc::SimpleRemoteEPC &SREPC,
+ unsigned SlabAllocateSize) {
+ llvm::orc::SharedMemoryMapper::SymbolAddrs SAs;
+ if (auto Err = SREPC.getBootstrapSymbols(
+ {{SAs.Instance,
+ llvm::orc::rt::ExecutorSharedMemoryMapperServiceInstanceName},
+ {SAs.Reserve,
+ llvm::orc::rt::ExecutorSharedMemoryMapperServiceReserveWrapperName},
+ {SAs.Initialize,
+ llvm::orc::rt::
+ ExecutorSharedMemoryMapperServiceInitializeWrapperName},
+ {SAs.Deinitialize,
+ llvm::orc::rt::
+ ExecutorSharedMemoryMapperServiceDeinitializeWrapperName},
+ {SAs.Release,
+ llvm::orc::rt::
+ ExecutorSharedMemoryMapperServiceReleaseWrapperName}}))
+ return std::move(Err);
+
+ size_t SlabSize;
+ if (llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows())
+ SlabSize = 1024 * 1024;
+ else
+ SlabSize = 1024 * 1024 * 1024;
+
+ if (SlabAllocateSize > 0)
+ SlabSize = SlabAllocateSize;
+
+ return llvm::orc::MapperJITLinkMemoryManager::CreateWithMapper<
+ llvm::orc::SharedMemoryMapper>(SlabSize, SREPC, SAs);
+}
+
+llvm::Expected<std::pair<std::unique_ptr<llvm::orc::SimpleRemoteEPC>, uint32_t>>
+IncrementalExecutor::launchExecutor(llvm::StringRef ExecutablePath,
+ bool UseSharedMemory,
+ unsigned SlabAllocateSize) {
+#ifndef LLVM_ON_UNIX
+ // FIXME: Add support for Windows.
+ return llvm::make_error<llvm::StringError>(
+ "-" + ExecutablePath + " not supported on non-unix platforms",
+ llvm::inconvertibleErrorCode());
+#elif !LLVM_ENABLE_THREADS
+ // Out of process mode using SimpleRemoteEPC depends on threads.
+ return llvm::make_error<llvm::StringError>(
+ "-" + ExecutablePath +
+ " requires threads, but LLVM was built with "
+ "LLVM_ENABLE_THREADS=Off",
+ llvm::inconvertibleErrorCode());
+#else
+
+ if (!llvm::sys::fs::can_execute(ExecutablePath))
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("Specified executor invalid: {0}", ExecutablePath),
+ llvm::inconvertibleErrorCode());
+
+ constexpr int ReadEnd = 0;
+ constexpr int WriteEnd = 1;
+
+ // Pipe FDs.
+ int ToExecutor[2];
+ int FromExecutor[2];
+
+ uint32_t ChildPID;
+
+ // Create pipes to/from the executor..
+ if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)
+ return llvm::make_error<llvm::StringError>(
+ "Unable to create pipe for executor", llvm::inconvertibleErrorCode());
+
+ ChildPID = fork();
+
+ if (ChildPID == 0) {
+ // In the child...
+
+ // Close the parent ends of the pipes
+ close(ToExecutor[WriteEnd]);
+ close(FromExecutor[ReadEnd]);
+
+ // Execute the child process.
+ std::unique_ptr<char[]> ExecutorPath, FDSpecifier;
+ {
+ ExecutorPath = std::make_unique<char[]>(ExecutablePath.size() + 1);
+ strcpy(ExecutorPath.get(), ExecutablePath.data());
+
+ std::string FDSpecifierStr("filedescs=");
+ FDSpecifierStr += llvm::utostr(ToExecutor[ReadEnd]);
+ FDSpecifierStr += ',';
+ FDSpecifierStr += llvm::utostr(FromExecutor[WriteEnd]);
+ FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);
+ strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
+ }
+
+ char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr};
+ int RC = execvp(ExecutorPath.get(), Args);
+ if (RC != 0) {
+ llvm::errs() << "unable to launch out-of-process executor \""
+ << ExecutorPath.get() << "\"\n";
+ exit(1);
+ }
+ }
+ // else we're the parent...
+
+ // Close the child ends of the pipes
+ close(ToExecutor[ReadEnd]);
+ close(FromExecutor[WriteEnd]);
+
+ llvm::orc::SimpleRemoteEPC::Setup S = llvm::orc::SimpleRemoteEPC::Setup();
+ if (UseSharedMemory)
+ S.CreateMemoryManager =
+ [SlabAllocateSize](llvm::orc::SimpleRemoteEPC &EPC) {
+ return createSharedMemoryManager(EPC, SlabAllocateSize);
+ };
+
+ auto EPCOrErr =
+ llvm::orc::SimpleRemoteEPC::Create<llvm::orc::FDSimpleRemoteEPCTransport>(
+ std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(
+ std::nullopt),
+ std::move(S), FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
+ if (!EPCOrErr)
+ return EPCOrErr.takeError();
+ return std::make_pair(std::move(*EPCOrErr), ChildPID);
+#endif
+}
+
+#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
+
+static Expected<int> connectTCPSocketImpl(std::string Host,
+ std::string PortStr) {
+ addrinfo *AI;
+ addrinfo Hints{};
+ Hints.ai_family = AF_INET;
+ Hints.ai_socktype = SOCK_STREAM;
+ Hints.ai_flags = AI_NUMERICSERV;
+
+ if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("address resolution failed ({0})", strerror(EC)),
+ llvm::inconvertibleErrorCode());
+ // Cycle through the returned addrinfo structures and connect to the first
+ // reachable endpoint.
+ int SockFD;
+ addrinfo *Server;
+ for (Server = AI; Server != nullptr; Server = Server->ai_next) {
+ // socket might fail, e.g. if the address family is not supported. Skip to
+ // the next addrinfo structure in such a case.
+ if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)
+ continue;
+
+ // If connect returns null, we exit the loop with a working socket.
+ if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
+ break;
+
+ close(SockFD);
+ }
+ freeaddrinfo(AI);
+
+ // If we reached the end of the loop without connecting to a valid endpoint,
+ // dump the last error that was logged in socket() or connect().
+ if (Server == nullptr)
+ return llvm::make_error<llvm::StringError>("invalid hostname",
+ llvm::inconvertibleErrorCode());
+
+ return SockFD;
+}
+
+llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>
+IncrementalExecutor::connectTCPSocket(llvm::StringRef NetworkAddress,
+ bool UseSharedMemory,
+ unsigned SlabAllocateSize) {
+#ifndef LLVM_ON_UNIX
+ // FIXME: Add TCP support for Windows.
+ return llvm::make_error<llvm::StringError>(
+ "-" + NetworkAddress + " not supported on non-unix platforms",
+ llvm::inconvertibleErrorCode());
+#elif !LLVM_ENABLE_THREADS
+ // Out of process mode using SimpleRemoteEPC depends on threads.
+ return llvm::make_error<llvm::StringError>(
+ "-" + NetworkAddress +
+ " requires threads, but LLVM was built with "
+ "LLVM_ENABLE_THREADS=Off",
+ llvm::inconvertibleErrorCode());
+#else
+
+ auto CreateErr = [NetworkAddress](Twine Details) {
+ return llvm::make_error<llvm::StringError>(
+ formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress,
+ Details),
+ llvm::inconvertibleErrorCode());
+ };
+
+ StringRef Host, PortStr;
+ std::tie(Host, PortStr) = NetworkAddress.split(':');
+ if (Host.empty())
+ return CreateErr("Host name for -" + NetworkAddress + " can not be empty");
+ if (PortStr.empty())
+ return CreateErr("Port number in -" + NetworkAddress + " can not be empty");
+ int Port = 0;
+ if (PortStr.getAsInteger(10, Port))
+ return CreateErr("Port number '" + PortStr + "' is not a valid integer");
+
+ Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());
+ if (!SockFD)
+ return SockFD.takeError();
+
+ llvm::orc::SimpleRemoteEPC::Setup S = llvm::orc::SimpleRemoteEPC::Setup();
+ if (UseSharedMemory)
+ S.CreateMemoryManager =
+ [SlabAllocateSize](llvm::orc::SimpleRemoteEPC &EPC) {
+ return createSharedMemoryManager(EPC, SlabAllocateSize);
+ };
+
+ return llvm::orc::SimpleRemoteEPC::Create<
+ llvm::orc::FDSimpleRemoteEPCTransport>(
+ std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(
+ std::nullopt),
+ std::move(S), *SockFD, *SockFD);
+#endif
+}
+#endif // _WIN32
+
} // namespace clang