1//===--- IncrementalExecutor.cpp - Incremental Execution --------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This has the implementation of the base facilities for incremental execution.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/Interpreter/IncrementalExecutor.h"
14#include "OrcIncrementalExecutor.h"
15
16#include "clang/Basic/TargetInfo.h"
17#include "clang/Config/config.h"
18#include "clang/Driver/Compilation.h"
19#include "clang/Driver/Driver.h"
20#include "clang/Driver/ToolChain.h"
21
22#include "llvm/ADT/SmallString.h"
23#include "llvm/ADT/SmallVector.h"
24#include "llvm/ADT/StringRef.h"
25#include "llvm/ADT/Twine.h"
26
27#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
28#include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h"
29#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
30#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
31#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
32#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
33#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
34#include "llvm/ExecutionEngine/Orc/LLJIT.h"
35#include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"
36#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
37#include "llvm/ExecutionEngine/Orc/SharedMemoryMapSPS.h"
38#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
39
40#include "llvm/Support/Error.h"
41#include "llvm/Support/FileSystem.h"
42#include "llvm/Support/FormatVariadic.h"
43#include "llvm/Support/Path.h"
44#include "llvm/Support/raw_ostream.h"
45
46#include "llvm/TargetParser/Host.h"
47
48#include <array>
49#include <functional>
50#include <memory>
51#include <optional>
52#include <string>
53#include <utility>
54
55#ifdef LLVM_ON_UNIX
56#include <netdb.h>
57#include <netinet/in.h>
58#include <sys/socket.h>
59#include <unistd.h>
60#endif
61
62// Address of the host's emulated-TLS runtime entry point, or null if the host
63// cannot provide one. clang-repl's JIT always lowers thread_local to emulated
64// TLS (JITTargetMachineBuilder forces EmulatedTLS on), so JIT'd code references
65// __emutls_get_address on every target. That symbol lives in the compiler
66// runtime -- libgcc_s.so on a glibc toolchain, or the compiler-rt builtins
67// static archive on Darwin and on compiler-rt-rtlib toolchains. When it is only
68// in a static archive and nothing else references it, it is never linked in and
69// ORC's process-symbol lookup cannot resolve it. Referencing it here
70// force-links the archive member so it is present regardless of how the host
71// provides it. Defined if available at configure time
72// (CLANG_HAVE_EMUTLS_GET_ADDRESS). When unavailable, thread_locals instead rely
73// on process-symbol lookup.
74#if CLANG_HAVE_EMUTLS_GET_ADDRESS
75extern "C" void *__emutls_get_address(void *);
76static void *getEmuTLSGetAddressPtr() {
77 return reinterpret_cast<void *>(&__emutls_get_address);
78}
79#else
80static void *getEmuTLSGetAddressPtr() { return nullptr; }
81#endif
82
83namespace clang {
84IncrementalExecutorBuilder::~IncrementalExecutorBuilder() = default;
85
86static llvm::Expected<llvm::orc::JITTargetMachineBuilder>
87createJITTargetMachineBuilder(const llvm::Triple &TT) {
88 if (TT.getTriple() == llvm::sys::getProcessTriple())
89 // This fails immediately if the target backend is not registered
90 return llvm::orc::JITTargetMachineBuilder::detectHost();
91
92 // If the target backend is not registered, LLJITBuilder::create() will fail
93 return llvm::orc::JITTargetMachineBuilder(TT);
94}
95
96static llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
97createDefaultJITBuilder(llvm::orc::JITTargetMachineBuilder JTMB) {
98 auto JITBuilder = std::make_unique<llvm::orc::LLJITBuilder>();
99 JITBuilder->setJITTargetMachineBuilder(std::move(JTMB));
100 JITBuilder->setPrePlatformSetup([](llvm::orc::LLJIT &J) {
101 // Try to enable debugging of JIT'd code (only works with JITLink for
102 // ELF and MachO).
103 consumeError(Err: llvm::orc::enableDebuggerSupport(J));
104 return llvm::Error::success();
105 });
106 return std::move(JITBuilder);
107}
108
109Expected<std::unique_ptr<llvm::jitlink::JITLinkMemoryManager>>
110createSharedMemoryManager(llvm::orc::ExecutorProcessControl &EPC,
111 unsigned SlabAllocateSize) {
112 auto &ES = EPC.getExecutionSession();
113 auto B = llvm::orc::sps::createSharedMemoryMapBindings(ES);
114 if (!B)
115 return B.takeError();
116
117 size_t SlabSize;
118 if (llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows())
119 SlabSize = 1024 * 1024;
120 else
121 SlabSize = 1024 * 1024 * 1024;
122
123 if (SlabAllocateSize > 0)
124 SlabSize = SlabAllocateSize;
125
126 return llvm::orc::MapperJITLinkMemoryManager::CreateWithMapper<
127 llvm::orc::SharedMemoryMapper>(ReservationGranularity: SlabSize, A&: ES, A: std::move(*B));
128}
129
130static llvm::Expected<
131 std::pair<std::unique_ptr<llvm::orc::SimpleRemoteEPC>, uint32_t>>
132launchExecutor(llvm::StringRef ExecutablePath,
133 std::function<void()> CustomizeFork) {
134#ifndef LLVM_ON_UNIX
135 // FIXME: Add support for Windows.
136 return llvm::make_error<llvm::StringError>(
137 "-" + ExecutablePath + " not supported on non-unix platforms",
138 llvm::inconvertibleErrorCode());
139#elif !LLVM_ENABLE_THREADS
140 // Out of process mode using SimpleRemoteEPC depends on threads.
141 return llvm::make_error<llvm::StringError>(
142 "-" + ExecutablePath +
143 " requires threads, but LLVM was built with "
144 "LLVM_ENABLE_THREADS=Off",
145 llvm::inconvertibleErrorCode());
146#else
147
148 if (!llvm::sys::fs::can_execute(Path: ExecutablePath))
149 return llvm::make_error<llvm::StringError>(
150 Args: llvm::formatv(Fmt: "Specified executor invalid: {0}", Vals&: ExecutablePath),
151 Args: llvm::inconvertibleErrorCode());
152
153 constexpr int ReadEnd = 0;
154 constexpr int WriteEnd = 1;
155
156 // Pipe FDs.
157 int ToExecutor[2];
158 int FromExecutor[2];
159
160 uint32_t ChildPID;
161
162 // Create pipes to/from the executor..
163 if (pipe(pipedes: ToExecutor) != 0 || pipe(pipedes: FromExecutor) != 0)
164 return llvm::make_error<llvm::StringError>(
165 Args: "Unable to create pipe for executor", Args: llvm::inconvertibleErrorCode());
166
167 ChildPID = fork();
168
169 if (ChildPID == 0) {
170 // In the child...
171
172 // Close the parent ends of the pipes
173 close(fd: ToExecutor[WriteEnd]);
174 close(fd: FromExecutor[ReadEnd]);
175
176 if (CustomizeFork)
177 CustomizeFork();
178
179 // Execute the child process.
180 std::unique_ptr<char[]> ExecutorPath, FDSpecifier;
181 {
182 ExecutorPath = std::make_unique<char[]>(num: ExecutablePath.size() + 1);
183 strcpy(dest: ExecutorPath.get(), src: ExecutablePath.data());
184
185 std::string FDSpecifierStr("filedescs=");
186 FDSpecifierStr += llvm::utostr(X: ToExecutor[ReadEnd]);
187 FDSpecifierStr += ',';
188 FDSpecifierStr += llvm::utostr(X: FromExecutor[WriteEnd]);
189 FDSpecifier = std::make_unique<char[]>(num: FDSpecifierStr.size() + 1);
190 strcpy(dest: FDSpecifier.get(), src: FDSpecifierStr.c_str());
191 }
192
193 char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr};
194 int RC = execvp(file: ExecutorPath.get(), argv: Args);
195 if (RC != 0) {
196 llvm::errs() << "unable to launch out-of-process executor \""
197 << ExecutorPath.get() << "\"\n";
198 exit(status: 1);
199 }
200 }
201 // else we're the parent...
202
203 // Close the child ends of the pipes
204 close(fd: ToExecutor[ReadEnd]);
205 close(fd: FromExecutor[WriteEnd]);
206
207 auto EPCOrErr =
208 llvm::orc::SimpleRemoteEPC::Create<llvm::orc::FDSimpleRemoteEPCTransport>(
209 D: std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(
210 args: std::nullopt),
211 TransportTCtorArgs&: FromExecutor[ReadEnd], TransportTCtorArgs&: ToExecutor[WriteEnd]);
212 if (!EPCOrErr)
213 return EPCOrErr.takeError();
214 return std::make_pair(x: std::move(*EPCOrErr), y&: ChildPID);
215#endif
216}
217
218#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
219
220static Expected<int> connectTCPSocketImpl(std::string Host,
221 std::string PortStr) {
222 addrinfo *AI;
223 addrinfo Hints{};
224 Hints.ai_family = AF_INET;
225 Hints.ai_socktype = SOCK_STREAM;
226 Hints.ai_flags = AI_NUMERICSERV;
227
228 if (int EC = getaddrinfo(name: Host.c_str(), service: PortStr.c_str(), req: &Hints, pai: &AI))
229 return llvm::make_error<llvm::StringError>(
230 Args: llvm::formatv(Fmt: "address resolution failed ({0})", Vals: strerror(errnum: EC)),
231 Args: llvm::inconvertibleErrorCode());
232 // Cycle through the returned addrinfo structures and connect to the first
233 // reachable endpoint.
234 int SockFD;
235 addrinfo *Server;
236 for (Server = AI; Server != nullptr; Server = Server->ai_next) {
237 // socket might fail, e.g. if the address family is not supported. Skip to
238 // the next addrinfo structure in such a case.
239 if ((SockFD = socket(domain: AI->ai_family, type: AI->ai_socktype, protocol: AI->ai_protocol)) < 0)
240 continue;
241
242 // If connect returns null, we exit the loop with a working socket.
243 if (connect(fd: SockFD, addr: Server->ai_addr, len: Server->ai_addrlen) == 0)
244 break;
245
246 close(fd: SockFD);
247 }
248 freeaddrinfo(ai: AI);
249
250 // If we reached the end of the loop without connecting to a valid endpoint,
251 // dump the last error that was logged in socket() or connect().
252 if (Server == nullptr)
253 return llvm::make_error<llvm::StringError>(Args: "invalid hostname",
254 Args: llvm::inconvertibleErrorCode());
255
256 return SockFD;
257}
258
259static llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>
260connectTCPSocket(llvm::StringRef NetworkAddress) {
261#ifndef LLVM_ON_UNIX
262 // FIXME: Add TCP support for Windows.
263 return llvm::make_error<llvm::StringError>(
264 "-" + NetworkAddress + " not supported on non-unix platforms",
265 llvm::inconvertibleErrorCode());
266#elif !LLVM_ENABLE_THREADS
267 // Out of process mode using SimpleRemoteEPC depends on threads.
268 return llvm::make_error<llvm::StringError>(
269 "-" + NetworkAddress +
270 " requires threads, but LLVM was built with "
271 "LLVM_ENABLE_THREADS=Off",
272 llvm::inconvertibleErrorCode());
273#else
274
275 auto CreateErr = [NetworkAddress](Twine Details) {
276 return llvm::make_error<llvm::StringError>(
277 Args: formatv(Fmt: "Failed to connect TCP socket '{0}': {1}", Vals: NetworkAddress,
278 Vals&: Details),
279 Args: llvm::inconvertibleErrorCode());
280 };
281
282 StringRef Host, PortStr;
283 std::tie(args&: Host, args&: PortStr) = NetworkAddress.split(Separator: ':');
284 if (Host.empty())
285 return CreateErr("Host name for -" + NetworkAddress + " can not be empty");
286 if (PortStr.empty())
287 return CreateErr("Port number in -" + NetworkAddress + " can not be empty");
288 int Port = 0;
289 if (PortStr.getAsInteger(Radix: 10, Result&: Port))
290 return CreateErr("Port number '" + PortStr + "' is not a valid integer");
291
292 Expected<int> SockFD = connectTCPSocketImpl(Host: Host.str(), PortStr: PortStr.str());
293 if (!SockFD)
294 return SockFD.takeError();
295
296 return llvm::orc::SimpleRemoteEPC::Create<
297 llvm::orc::FDSimpleRemoteEPCTransport>(
298 D: std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(
299 args: std::nullopt),
300 TransportTCtorArgs&: *SockFD, TransportTCtorArgs&: *SockFD);
301#endif
302}
303#endif // _WIN32
304
305static llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
306createLLJITBuilder(std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
307 llvm::StringRef OrcRuntimePath) {
308 auto JTMB = createJITTargetMachineBuilder(TT: EPC->getTargetTriple());
309 if (!JTMB)
310 return JTMB.takeError();
311 auto JB = createDefaultJITBuilder(JTMB: std::move(*JTMB));
312 if (!JB)
313 return JB.takeError();
314
315 (*JB)->setExecutorProcessControl(std::move(EPC));
316 (*JB)->setPlatformSetUp(
317 llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
318
319 return std::move(*JB);
320}
321
322static llvm::Expected<
323 std::pair<std::unique_ptr<llvm::orc::LLJITBuilder>, uint32_t>>
324outOfProcessJITBuilder(const IncrementalExecutorBuilder &IncrExecutorBuilder) {
325 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
326 uint32_t childPid = -1;
327 if (!IncrExecutorBuilder.OOPExecutor.empty()) {
328 // Launch an out-of-process executor locally in a child process.
329 auto ResultOrErr = launchExecutor(ExecutablePath: IncrExecutorBuilder.OOPExecutor,
330 CustomizeFork: IncrExecutorBuilder.CustomizeFork);
331 if (!ResultOrErr)
332 return ResultOrErr.takeError();
333 childPid = ResultOrErr->second;
334 auto EPCOrErr = std::move(ResultOrErr->first);
335 EPC = std::move(EPCOrErr);
336 } else if (IncrExecutorBuilder.OOPExecutorConnect != "") {
337#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
338 auto EPCOrErr = connectTCPSocket(NetworkAddress: IncrExecutorBuilder.OOPExecutorConnect);
339 if (!EPCOrErr)
340 return EPCOrErr.takeError();
341 EPC = std::move(*EPCOrErr);
342#else
343 return llvm::make_error<llvm::StringError>(
344 "Out-of-process JIT over TCP is not supported on this platform",
345 std::error_code());
346#endif
347 }
348
349 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
350 if (EPC) {
351 auto JBOrErr =
352 createLLJITBuilder(EPC: std::move(EPC), OrcRuntimePath: IncrExecutorBuilder.OrcRuntimePath);
353 if (!JBOrErr)
354 return JBOrErr.takeError();
355 JB = std::move(*JBOrErr);
356
357 if (IncrExecutorBuilder.UseSharedMemory)
358 JB->setMemoryManagerCreator(
359 [SlabAllocateSize = IncrExecutorBuilder.SlabAllocateSize](
360 llvm::orc::ExecutionSession &ES) {
361 return createSharedMemoryManager(EPC&: ES.getExecutorProcessControl(),
362 SlabAllocateSize);
363 });
364 }
365
366 return std::make_pair(x: std::move(JB), y&: childPid);
367}
368
369llvm::Expected<std::unique_ptr<IncrementalExecutor>>
370IncrementalExecutorBuilder::create(llvm::orc::ThreadSafeContext &TSC,
371 const clang::TargetInfo &TI) {
372 if (IE)
373 return std::move(IE);
374 llvm::Triple TT = TI.getTriple();
375 if (!TT.isOSWindows() && IsOutOfProcess) {
376 if (!JITBuilder) {
377 auto ResOrErr = outOfProcessJITBuilder(IncrExecutorBuilder: *this);
378 if (!ResOrErr)
379 return ResOrErr.takeError();
380 JITBuilder = std::move(ResOrErr->first);
381 ExecutorPID = ResOrErr->second;
382 }
383 if (!JITBuilder)
384 return llvm::make_error<llvm::StringError>(
385 Args: "Operation failed. No LLJITBuilder for out-of-process JIT",
386 Args: std::error_code());
387 }
388
389 if (!JITBuilder) {
390 auto JTMB = createJITTargetMachineBuilder(TT);
391 if (!JTMB)
392 return JTMB.takeError();
393 if (CM)
394 JTMB->setCodeModel(CM);
395 auto JB = createDefaultJITBuilder(JTMB: std::move(*JTMB));
396 if (!JB)
397 return JB.takeError();
398 JITBuilder = std::move(*JB);
399 // TODO: Switch to native TLS once clang-repl can adopt the ORC runtime
400 // (which provides __emutls_get_address and supports the full TLS
401 // lifecycle). That will also remove the in-process-only constraint below.
402 //
403 // clang-repl lowers thread_local to emulated TLS on every target (see
404 // JITTargetMachineBuilder), so JIT'd code calls __emutls_get_address. When
405 // the host cannot resolve that symbol through process-symbol lookup
406 // (Darwin, and ELF toolchains that link compiler-rt builtins rather than
407 // libgcc_s), define the force-linked host symbol (see
408 // getEmuTLSGetAddressPtr) as an absolute symbol so it is visible to JIT'd
409 // code. This is harmless where process-symbol lookup would already resolve
410 // it: an already-defined symbol shadows the process-symbols generator.
411 // In-process execution only -- the host address is meaningless in an
412 // out-of-process executor.
413 if (void *EmuTLSGetAddress = getEmuTLSGetAddressPtr())
414 JITBuilder->setNotifyCreatedCallback(
415 [EmuTLSGetAddress](llvm::orc::LLJIT &J) {
416 auto &JD = J.getProcessSymbolsJITDylib()
417 ? *J.getProcessSymbolsJITDylib()
418 : J.getMainJITDylib();
419 return JD.define(MU: llvm::orc::absoluteSymbols(
420 Symbols: {{J.mangleAndIntern(UnmangledName: "__emutls_get_address"),
421 {llvm::orc::ExecutorAddr::fromPtr(Ptr: EmuTLSGetAddress),
422 llvm::JITSymbolFlags::Exported}}}));
423 });
424 }
425
426 llvm::Error Err = llvm::Error::success();
427 std::unique_ptr<IncrementalExecutor> Executor =
428 std::make_unique<OrcIncrementalExecutor>(args&: TSC, args&: *JITBuilder, args&: Err);
429
430 if (Err)
431 return std::move(Err);
432
433 return std::move(Executor);
434}
435
436llvm::Error IncrementalExecutorBuilder::UpdateOrcRuntimePath(
437 const clang::driver::Compilation &C) {
438 if (!IsOutOfProcess)
439 return llvm::Error::success();
440
441 const clang::driver::Driver &D = C.getDriver();
442 const clang::driver::ToolChain &TC = C.getDefaultToolChain();
443
444 llvm::SmallVector<std::string, 2> OrcRTLibNames;
445
446 // Get canonical compiler-rt path
447 std::string CompilerRTPath = TC.getCompilerRT(Args: C.getArgs(), Component: "orc_rt");
448 llvm::StringRef CanonicalFilename = llvm::sys::path::filename(path: CompilerRTPath);
449
450 if (CanonicalFilename.empty()) {
451 return llvm::make_error<llvm::StringError>(
452 Args: "Could not determine OrcRuntime filename from ToolChain",
453 Args: llvm::inconvertibleErrorCode());
454 }
455
456 OrcRTLibNames.push_back(Elt: CanonicalFilename.str());
457
458 // Derive legacy spelling (libclang_rt.orc_rt -> orc_rt)
459 llvm::StringRef LegacySuffix = CanonicalFilename;
460 if (LegacySuffix.consume_front(Prefix: "libclang_rt.")) {
461 OrcRTLibNames.push_back(Elt: ("lib" + LegacySuffix).str());
462 }
463
464 // Extract directory
465 llvm::SmallString<256> OrcRTDir(CompilerRTPath);
466 llvm::sys::path::remove_filename(path&: OrcRTDir);
467
468 llvm::SmallVector<std::string, 8> triedPaths;
469
470 auto findInDir = [&](llvm::StringRef Dir) -> std::optional<std::string> {
471 for (const auto &LibName : OrcRTLibNames) {
472 llvm::SmallString<256> FullPath = Dir;
473 llvm::sys::path::append(path&: FullPath, a: LibName);
474 if (llvm::sys::fs::exists(Path: FullPath))
475 return std::string(FullPath.str());
476 triedPaths.push_back(Elt: std::string(FullPath.str()));
477 }
478 return std::nullopt;
479 };
480
481 // Try the primary directory first
482 if (auto Found = findInDir(OrcRTDir)) {
483 OrcRuntimePath = *Found;
484 return llvm::Error::success();
485 }
486
487 // We want to find the relative path from the Driver to the OrcRTDir
488 // to replicate that structure elsewhere if needed.
489 llvm::StringRef Rel = OrcRTDir.str();
490 if (!Rel.consume_front(Prefix: llvm::sys::path::parent_path(path: D.Dir))) {
491 return llvm::make_error<llvm::StringError>(
492 Args: llvm::formatv(Fmt: "OrcRuntime library path ({0}) is not located within the "
493 "Clang resource directory ({1}). Check your installation "
494 "or provide an explicit path via -resource-dir.",
495 Vals&: OrcRTDir, Vals: D.Dir)
496 .str(),
497 Args: llvm::inconvertibleErrorCode());
498 }
499
500 // Generic Backward Search (Climbing the tree)
501 // This is useful for unit tests or relocated toolchains
502 llvm::SmallString<256> Cursor(D.Dir); // Start from the driver directory
503 while (llvm::sys::path::has_parent_path(path: Cursor)) {
504 Cursor = llvm::sys::path::parent_path(path: Cursor).str();
505 llvm::SmallString<256> Candidate = Cursor;
506 llvm::sys::path::append(path&: Candidate, a: Rel);
507
508 if (auto Found = findInDir(Candidate)) {
509 OrcRuntimePath = *Found;
510 return llvm::Error::success();
511 }
512
513 // Safety check
514 if (triedPaths.size() > 32)
515 break;
516 }
517
518 // Build a helpful error string
519 std::string Joined;
520 for (size_t i = 0; i < triedPaths.size(); ++i) {
521 if (i > 0)
522 Joined += "\n ";
523 Joined += triedPaths[i];
524 }
525
526 return llvm::make_error<llvm::StringError>(
527 Args: llvm::formatv(Fmt: "OrcRuntime library not found. Checked: {0}",
528 Vals: Joined.empty() ? "<none>" : Joined)
529 .str(),
530 Args: std::make_error_code(e: std::errc::no_such_file_or_directory));
531}
532
533} // end namespace clang
534