[llvm] [orc-rt] Add a scheme for system-specific code. (PR #219648)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 29 01:05:55 PDT 2026
https://github.com/lhames created https://github.com/llvm/llvm-project/pull/219648
System-specific code was written two ad-hoc ways: .cpp files selected by CMake, and Unix/*.inc textually included behind #if ladders.
Those operations are now declared in orc-rt-internal/support/sys/, with one implementation per capability directory (posix/, darwin/, windows/). CMake composes capability lists rather than selecting an OS list. E.g. POSIX targets get posix/ plus their OS directory. A file belongs in a shared list only if it is uniform across that list's members; where a function needs an OS conditional it moves into an OS-specific directory instead. The "Target OS ... unsupported" #error ladders go away with the textual includes -- components no longer include system code at all, so the diagnostic belongs in CMake.
hostOS* becomes the orc_rt::sys namespace, matching llvm::sys.
Cache invalidation is the exception, since it wants to inline: it is declared in sys/CacheControl.h, which selects a per-system definition header. Its generic path now uses __builtin___clear_cache instead of declaring __clear_cache, which forced an opaque call.
>From 851606accdc4e065ae2cf9da66a3668a7ce59dc6 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Sat, 29 Aug 2026 17:33:22 +1000
Subject: [PATCH] [orc-rt] Add a scheme for system-specific code.
System-specific code was written two ad-hoc ways: .cpp files selected by
CMake, and Unix/*.inc textually included behind #if ladders.
Those operations are now declared in orc-rt-internal/support/sys/, with
one implementation per capability directory (posix/, darwin/, windows/).
CMake composes capability lists rather than selecting an OS list. E.g.
POSIX targets get posix/ plus their OS directory. A file belongs in a
shared list only if it is uniform across that list's members; where a
function needs an OS conditional it moves into an OS-specific directory
instead. The "Target OS ... unsupported" #error ladders go away with the
textual includes -- components no longer include system code at all, so
the diagnostic belongs in CMake.
hostOS* becomes the orc_rt::sys namespace, matching llvm::sys.
Cache invalidation is the exception, since it wants to inline: it is
declared in sys/CacheControl.h, which selects a per-system definition
header. Its generic path now uses __builtin___clear_cache instead of
declaring __clear_cache, which forced an opaque call.
---
.../support/sys/CacheControl.h | 44 +++++++++
.../support/sys/DynamicLibrary.h | 48 ++++++++++
.../orc-rt-internal/support/sys/Memory.h | 44 +++++++++
.../support/sys/darwin/CacheControl.h | 31 +++++++
.../support/sys/posix/CacheControl.h | 31 +++++++
orc-rt/lib/bedrock/CMakeLists.txt | 31 +++++--
orc-rt/lib/bedrock/NativeDylibManager.cpp | 17 ++--
orc-rt/lib/bedrock/SimpleNativeMemoryMap.cpp | 16 +---
orc-rt/lib/bedrock/Unix/NativeDylibAPIs.inc | 72 ---------------
orc-rt/lib/bedrock/posix/DynamicLibrary.cpp | 92 +++++++++++++++++++
.../NativeMemoryAPIs.inc => posix/Memory.cpp} | 62 ++++++-------
11 files changed, 351 insertions(+), 137 deletions(-)
create mode 100644 orc-rt/include/orc-rt-internal/support/sys/CacheControl.h
create mode 100644 orc-rt/include/orc-rt-internal/support/sys/DynamicLibrary.h
create mode 100644 orc-rt/include/orc-rt-internal/support/sys/Memory.h
create mode 100644 orc-rt/include/orc-rt-internal/support/sys/darwin/CacheControl.h
create mode 100644 orc-rt/include/orc-rt-internal/support/sys/posix/CacheControl.h
delete mode 100644 orc-rt/lib/bedrock/Unix/NativeDylibAPIs.inc
create mode 100644 orc-rt/lib/bedrock/posix/DynamicLibrary.cpp
rename orc-rt/lib/bedrock/{Unix/NativeMemoryAPIs.inc => posix/Memory.cpp} (51%)
diff --git a/orc-rt/include/orc-rt-internal/support/sys/CacheControl.h b/orc-rt/include/orc-rt-internal/support/sys/CacheControl.h
new file mode 100644
index 0000000000000..3576f8b242dd8
--- /dev/null
+++ b/orc-rt/include/orc-rt-internal/support/sys/CacheControl.h
@@ -0,0 +1,44 @@
+//===- CacheControl.h - Instruction cache maintenance -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Host cache management APIs.
+//
+// Unlike the rest of sys/, where the build compiles one implementation .cpp per
+// system, these operations want to inline: on targets where they lower to
+// cache-maintenance instructions rather than a call, a cross-TU call would cost
+// more than the operation itself. So the declarations live here and the
+// definitions come from a per-system header selected below. The conditionals
+// are confined to this file; each implementation header is unconditional.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_INTERNAL_SUPPORT_SYS_CACHECONTROL_H
+#define ORC_RT_INTERNAL_SUPPORT_SYS_CACHECONTROL_H
+
+#include <cstddef>
+
+namespace orc_rt::sys {
+
+/// Make writes to [Addr, Addr + Size) visible to instruction fetch.
+///
+/// Call this after writing instructions to memory and before executing them.
+/// SimpleNativeMemoryMap does so for any segment made executable, so clients
+/// finalizing memory through it do not need to call this themselves.
+inline void clear_icache(void *Addr, size_t Size);
+
+} // namespace orc_rt::sys
+
+// Definition of the above. Selected here rather than by the build system so
+// that a reader of this header can see which implementation applies.
+#if defined(__APPLE__)
+#include "orc-rt-internal/support/sys/darwin/CacheControl.h"
+#else
+#include "orc-rt-internal/support/sys/posix/CacheControl.h"
+#endif
+
+#endif // ORC_RT_INTERNAL_SUPPORT_SYS_CACHECONTROL_H
diff --git a/orc-rt/include/orc-rt-internal/support/sys/DynamicLibrary.h b/orc-rt/include/orc-rt-internal/support/sys/DynamicLibrary.h
new file mode 100644
index 0000000000000..bf4576d743e1e
--- /dev/null
+++ b/orc-rt/include/orc-rt-internal/support/sys/DynamicLibrary.h
@@ -0,0 +1,48 @@
+//===--- DynamicLibrary.h - System dynamic library operations ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// The host dynamic-library operations that NativeDylibManager is built on.
+//
+// Exactly one implementation is compiled into the runtime, chosen by the build:
+// see lib/bedrock/posix/DynamicLibrary.cpp and its siblings. A target with no
+// dynamic loader has no native dylib manager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_INTERNAL_SUPPORT_SYS_DYNAMICLIBRARY_H
+#define ORC_RT_INTERNAL_SUPPORT_SYS_DYNAMICLIBRARY_H
+
+#include "orc-rt/support/Error.h"
+
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace orc_rt::sys {
+
+/// Returns a handle that looks up symbols in every library loaded into the
+/// process.
+void *globalLookupHandle();
+
+/// Load the library at the given path. Path must not be empty.
+Expected<void *> loadLibrary(const std::string &Path);
+
+/// Unload a library previously returned by loadLibrary.
+Error unloadLibrary(void *Handle);
+
+/// Look Names up in Handle, returning one result per name in order.
+///
+/// A result is nullopt if the name is not present in the library, and a
+/// (possibly null) address if it is: a symbol genuinely located at address zero
+/// is reported as null rather than as missing.
+std::vector<std::optional<void *>>
+lookupLibrarySymbols(void *Handle, const std::vector<std::string> &Names);
+
+} // namespace orc_rt::sys
+
+#endif // ORC_RT_INTERNAL_SUPPORT_SYS_DYNAMICLIBRARY_H
diff --git a/orc-rt/include/orc-rt-internal/support/sys/Memory.h b/orc-rt/include/orc-rt-internal/support/sys/Memory.h
new file mode 100644
index 0000000000000..3d9b920fb27de
--- /dev/null
+++ b/orc-rt/include/orc-rt-internal/support/sys/Memory.h
@@ -0,0 +1,44 @@
+//===- Memory.h - System memory operations ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// The host memory operations that SimpleNativeMemoryMap is built on.
+//
+// Exactly one implementation is compiled into the runtime, chosen by the build:
+// see lib/bedrock/posix/Memory.cpp and its siblings. A target that
+// cannot provide these has no native memory map.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_INTERNAL_SUPPORT_SYS_MEMORY_H
+#define ORC_RT_INTERNAL_SUPPORT_SYS_MEMORY_H
+
+#include "orc-rt/support/Error.h"
+#include "orc-rt/support/MemoryFlags.h"
+
+#include <cstddef>
+
+namespace orc_rt::sys {
+
+/// Reserve Size bytes of read/write memory. Returns null if Size is zero.
+///
+/// The returned range is not yet executable: use protectMemory to change
+/// its permissions.
+Expected<void *> reserveMemory(size_t Size);
+
+/// Release a range previously returned by reserveMemory.
+Error releaseMemory(void *Base, size_t Size);
+
+/// Set the permissions of a range previously returned by reserveMemory.
+///
+/// If MP includes Exec then the instruction cache is invalidated for the range,
+/// so callers do not need to do so themselves.
+Error protectMemory(void *Base, size_t Size, MemProt MP);
+
+} // namespace orc_rt::sys
+
+#endif // ORC_RT_INTERNAL_SUPPORT_SYS_MEMORY_H
diff --git a/orc-rt/include/orc-rt-internal/support/sys/darwin/CacheControl.h b/orc-rt/include/orc-rt-internal/support/sys/darwin/CacheControl.h
new file mode 100644
index 0000000000000..b2f73a9dfdaed
--- /dev/null
+++ b/orc-rt/include/orc-rt-internal/support/sys/darwin/CacheControl.h
@@ -0,0 +1,31 @@
+//===- CacheControl.h - Instruction cache maintenance on Darwin -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Darwin definitions for the operations declared in sys/CacheControl.h, which
+// is the header callers should include.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_INTERNAL_SUPPORT_SYS_DARWIN_CACHECONTROL_H
+#define ORC_RT_INTERNAL_SUPPORT_SYS_DARWIN_CACHECONTROL_H
+
+#include <cstddef>
+
+extern "C" void sys_icache_invalidate(const void *Addr, size_t Size);
+
+namespace orc_rt::sys {
+
+inline void clear_icache(void *Addr, size_t Size) {
+ // libSystem's implementation, which knows the cache geometry of the running
+ // CPU. Preferred over __builtin___clear_cache on Darwin.
+ sys_icache_invalidate(Addr, Size);
+}
+
+} // namespace orc_rt::sys
+
+#endif // ORC_RT_INTERNAL_SUPPORT_SYS_DARWIN_CACHECONTROL_H
diff --git a/orc-rt/include/orc-rt-internal/support/sys/posix/CacheControl.h b/orc-rt/include/orc-rt-internal/support/sys/posix/CacheControl.h
new file mode 100644
index 0000000000000..00fe332e68a00
--- /dev/null
+++ b/orc-rt/include/orc-rt-internal/support/sys/posix/CacheControl.h
@@ -0,0 +1,31 @@
+//===- CacheControl.h - Instruction cache maintenance, generic --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic definitions for the operations declared in sys/CacheControl.h, which
+// is the header callers should include.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_INTERNAL_SUPPORT_SYS_POSIX_CACHECONTROL_H
+#define ORC_RT_INTERNAL_SUPPORT_SYS_POSIX_CACHECONTROL_H
+
+#include <cstddef>
+
+namespace orc_rt::sys {
+
+inline void clear_icache(void *Addr, size_t Size) {
+ // A builtin rather than a declaration of __clear_cache, so that the compiler
+ // can emit the cache-maintenance instructions inline where the target has
+ // them, instead of an opaque call.
+ char *Start = static_cast<char *>(Addr);
+ __builtin___clear_cache(Start, Start + Size);
+}
+
+} // namespace orc_rt::sys
+
+#endif // ORC_RT_INTERNAL_SUPPORT_SYS_POSIX_CACHECONTROL_H
diff --git a/orc-rt/lib/bedrock/CMakeLists.txt b/orc-rt/lib/bedrock/CMakeLists.txt
index 5d1e084357552..e27ef29276f63 100644
--- a/orc-rt/lib/bedrock/CMakeLists.txt
+++ b/orc-rt/lib/bedrock/CMakeLists.txt
@@ -34,6 +34,21 @@ elseif(ORC_RT_LOG_BACKEND STREQUAL "os_log")
list(APPEND ORC_RT_SOURCES Logging_oslog.cpp)
endif()
+# System implementations are composed, not merely selected: a target gets one
+# source list per capability it has. POSIX systems share posix/, and add their
+# OS-specific list on top; Windows shares nothing with them.
+#
+# A file belongs in a shared list only if it is uniform across every member of
+# it. Where a function needs an OS conditional, it moves down into the
+# per-OS lists instead of growing an #ifdef here -- or, if it wants to inline,
+# becomes a dispatch header under include/orc-rt-internal/ (see
+# support/sys/CacheControl.h).
+
+set(ORC_RT_POSIX_SOURCES
+ posix/DynamicLibrary.cpp
+ posix/Memory.cpp
+)
+
set(ORC_RT_DARWIN_SOURCES
darwin/CPUFeatures.cpp
darwin/TargetTriple.cpp
@@ -50,15 +65,15 @@ set(ORC_RT_WINDOWS_SOURCES
)
if (APPLE)
- list(APPEND ORC_RT_SOURCES ${ORC_RT_DARWIN_SOURCES})
+ list(APPEND ORC_RT_SOURCES ${ORC_RT_POSIX_SOURCES} ${ORC_RT_DARWIN_SOURCES})
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
- list(APPEND ORC_RT_SOURCES ${ORC_RT_LINUX_SOURCES})
- elseif (WIN32)
- list(APPEND ORC_RT_SOURCES ${ORC_RT_WINDOWS_SOURCES})
- else()
- message(WARNING
- "orc-rt: no platform implementation for ${CMAKE_SYSTEM_NAME}; "
- "Add an orc-rt/lib/bedrock/<platform>/ directory")
+ list(APPEND ORC_RT_SOURCES ${ORC_RT_POSIX_SOURCES} ${ORC_RT_LINUX_SOURCES})
+elseif (WIN32)
+ list(APPEND ORC_RT_SOURCES ${ORC_RT_WINDOWS_SOURCES})
+else()
+ message(WARNING
+ "orc-rt: no system implementation for ${CMAKE_SYSTEM_NAME}; "
+ "add an orc-rt/lib/bedrock/<system>/ directory and compose it above")
endif()
add_library(orc-rt-bedrock STATIC ${ORC_RT_SOURCES})
diff --git a/orc-rt/lib/bedrock/NativeDylibManager.cpp b/orc-rt/lib/bedrock/NativeDylibManager.cpp
index fd49413f2eb8d..e81cfc8618cfe 100644
--- a/orc-rt/lib/bedrock/NativeDylibManager.cpp
+++ b/orc-rt/lib/bedrock/NativeDylibManager.cpp
@@ -11,14 +11,9 @@
//===----------------------------------------------------------------------===//
#include "orc-rt/bedrock/NativeDylibManager.h"
+#include "orc-rt-internal/support/sys/DynamicLibrary.h"
#include "orc-rt/bedrock/Session.h"
-#if defined(__APPLE__) || defined(__linux__)
-#include "Unix/NativeDylibAPIs.inc"
-#else
-#error "Target OS dylib APIs unsupported"
-#endif
-
namespace orc_rt {
Expected<std::unique_ptr<NativeDylibManager>>
@@ -46,16 +41,16 @@ void NativeDylibManager::load(OnLoadCompleteFn &&OnComplete, std::string Path) {
// Empty path -> global handle; no shutdown callback (RTLD_DEFAULT
// mustn't be dlclose'd).
if (Path.empty())
- return OnComplete(hostOSGetGlobalLookupHandle());
+ return OnComplete(sys::globalLookupHandle());
- auto H = hostOSLoadLibrary(Path);
+ auto H = sys::loadLibrary(Path);
if (!H)
return OnComplete(H.takeError());
// Capture S by reference, rather than this, so that the callback remains
// valid even if the NativeDylibManager is destroyed prior to shutdown.
S.addOnShutdown([&S = this->S, Handle = *H]() {
- if (auto Err = hostOSUnloadLibrary(Handle))
+ if (auto Err = sys::unloadLibrary(Handle))
S.reportError(std::move(Err));
});
OnComplete(std::move(H));
@@ -68,9 +63,9 @@ void NativeDylibManager::lookup(OnLookupCompleteFn &&OnLookupComplete,
for (auto &S : Symbols)
Names.push_back(std::move(S.first));
- auto Addrs = hostOSLibraryLookup(Handle, Names);
+ auto Addrs = sys::lookupLibrarySymbols(Handle, Names);
- // Convert weak-missing entries (empty optional from hostOSLibraryLookup)
+ // Convert weak-missing entries (empty optional from lookupLibrarySymbols)
// to a present zero address. This matches the resolve semantics of
// llvm::orc::rt_bootstrap::SimpleExecutorDylibManager: an empty optional
// in the result signals a missing required symbol, while a missing
diff --git a/orc-rt/lib/bedrock/SimpleNativeMemoryMap.cpp b/orc-rt/lib/bedrock/SimpleNativeMemoryMap.cpp
index fcd2c5c4066f4..53094a2725ab3 100644
--- a/orc-rt/lib/bedrock/SimpleNativeMemoryMap.cpp
+++ b/orc-rt/lib/bedrock/SimpleNativeMemoryMap.cpp
@@ -15,16 +15,11 @@
#include "orc-rt/bedrock/SimpleNativeMemoryMap.h"
#include "orc-rt-internal/support/StringExtras.h"
+#include "orc-rt-internal/support/sys/Memory.h"
#include "orc-rt/bedrock/Session.h"
#include <optional>
-#if defined(__APPLE__) || defined(__linux__)
-#include "Unix/NativeMemoryAPIs.inc"
-#else
-#error "Target OS memory APIs unsupported"
-#endif
-
namespace orc_rt {
Expected<std::unique_ptr<SimpleNativeMemoryMap>>
@@ -57,14 +52,13 @@ void SimpleNativeMemoryMap::reserve(OnReserveCompleteFn &&OnComplete,
.str()));
}
- auto Addr = hostOSMemoryReserve(Size);
+ auto Addr = sys::reserveMemory(Size);
if (!Addr)
return OnComplete(Addr.takeError());
{
std::scoped_lock<std::mutex> Lock(M);
- assert(!Slabs.count(*Addr) &&
- "hostOSMemoryReserve returned duplicate addresses");
+ assert(!Slabs.count(*Addr) && "reserveMemory returned duplicate addresses");
Slabs.emplace(std::make_pair(*Addr, SlabInfo(Size)));
}
@@ -95,7 +89,7 @@ void SimpleNativeMemoryMap::release(OnReleaseCompleteFn &&OnComplete,
for (auto &[Addr, DAAs] : SI->DeallocActions)
runDeallocActions(std::move(DAAs), ReportErrorsViaSession(S));
- OnComplete(hostOSMemoryRelease(Addr, SI->Size));
+ OnComplete(sys::releaseMemory(Addr, SI->Size));
}
void SimpleNativeMemoryMap::releaseMultiple(OnReleaseCompleteFn &&OnComplete,
@@ -132,7 +126,7 @@ void SimpleNativeMemoryMap::initialize(OnInitializeCompleteFn &&OnComplete,
if (size_t ZeroFillSize = S.Size - S.Content.size())
memset(S.Address + S.Content.size(), 0, ZeroFillSize);
- if (auto Err = hostOSMemoryProtect(S.Address, S.Size, S.AG.getMemProt()))
+ if (auto Err = sys::protectMemory(S.Address, S.Size, S.AG.getMemProt()))
return OnComplete(std::move(Err));
switch (S.AG.getMemLifetime()) {
diff --git a/orc-rt/lib/bedrock/Unix/NativeDylibAPIs.inc b/orc-rt/lib/bedrock/Unix/NativeDylibAPIs.inc
deleted file mode 100644
index e1ef18ad694a8..0000000000000
--- a/orc-rt/lib/bedrock/Unix/NativeDylibAPIs.inc
+++ /dev/null
@@ -1,72 +0,0 @@
-//===- NativeDylibAPIs.inc --------------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Generic wrappers for POSIX dlfcn.h APIs.
-//
-//===----------------------------------------------------------------------===//
-
-#include "orc-rt-internal/support/StringExtras.h"
-#include "orc-rt/support/Error.h"
-
-#include <dlfcn.h>
-
-namespace {
-
-inline void *hostOSGetGlobalLookupHandle() { return RTLD_DEFAULT; }
-
-orc_rt::Expected<void *> hostOSLoadLibrary(const std::string &Path) {
- assert(!Path.empty() && "hostOSLoadLibray doesn't support empty paths");
- void *H = dlopen(Path.c_str(), RTLD_LAZY | RTLD_LOCAL);
- if (H == nullptr)
- return orc_rt::make_error<orc_rt::StringError>(
- (orc_rt::StringOutputStream()
- << "error loading \"" << Path << "\": " << dlerror())
- .str());
-
- return H;
-}
-
-orc_rt::Error hostOSUnloadLibrary(void *Handle) {
- if (dlclose(Handle) != 0)
- return orc_rt::make_error<orc_rt::StringError>(
- (orc_rt::StringOutputStream()
- << "error unloading " << Handle << ": " << dlerror())
- .str());
- return orc_rt::Error::success();
-}
-
-std::vector<std::optional<void *>>
-hostOSLibraryLookup(void *Handle, const std::vector<std::string> &Names) {
- std::vector<std::optional<void *>> Result;
- Result.reserve(Names.size());
- // Reset dlerror so we can distinguish "dlsym returned null because the
- // symbol is present at address 0" from "dlsym returned null because the
- // symbol isn't in the library" via per-iteration dlerror() checks.
- dlerror();
- for (const auto &Name : Names) {
-#if defined(__APPLE__)
- if (Name.empty() || Name[0] != '_') {
- Result.push_back(std::nullopt);
- continue;
- }
- const char *LookupName = Name.c_str() + 1;
-#else
- const char *LookupName = Name.c_str();
-#endif // defined(__APPLE__)
-
- if (void *Addr = dlsym(Handle, LookupName))
- Result.push_back(Addr);
- else if (dlerror() == nullptr)
- Result.push_back(nullptr);
- else
- Result.push_back(std::nullopt);
- }
- return Result;
-}
-
-} // namespace
diff --git a/orc-rt/lib/bedrock/posix/DynamicLibrary.cpp b/orc-rt/lib/bedrock/posix/DynamicLibrary.cpp
new file mode 100644
index 0000000000000..931120a167acc
--- /dev/null
+++ b/orc-rt/lib/bedrock/posix/DynamicLibrary.cpp
@@ -0,0 +1,92 @@
+//===- DynamicLibrary.cpp - POSIX dynamic library operations ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of orc-rt-internal/support/sys/DynamicLibrary.h on POSIX
+// systems, in terms of dlfcn.h.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt-internal/support/sys/DynamicLibrary.h"
+
+#include "orc-rt-internal/support/StringExtras.h"
+
+#include <cassert>
+#include <dlfcn.h>
+
+namespace orc_rt::sys {
+
+namespace {
+
+/// Map an orc-rt symbol name to the name dlsym expects, or nullopt if the name
+/// cannot name a symbol on this system.
+///
+/// This is the whole of the OS difference in lookupLibrarySymbols, so it is
+/// forked here rather than in its caller.
+std::optional<const char *> toDLSymName(const std::string &Name) {
+#if defined(__APPLE__)
+ // Mach-O prefixes global symbols with '_', but dlsym takes the unprefixed
+ // form, so a name that lacks the prefix cannot name a global symbol.
+ if (Name.empty() || Name[0] != '_')
+ return std::nullopt;
+ return Name.c_str() + 1;
+#else
+ return Name.c_str();
+#endif
+}
+
+} // namespace
+
+void *globalLookupHandle() { return RTLD_DEFAULT; }
+
+Expected<void *> loadLibrary(const std::string &Path) {
+ assert(!Path.empty() && "loadLibrary doesn't support empty paths");
+ void *H = dlopen(Path.c_str(), RTLD_LAZY | RTLD_LOCAL);
+ if (H == nullptr)
+ return make_error<StringError>((StringOutputStream()
+ << "error loading \"" << Path
+ << "\": " << dlerror())
+ .str());
+
+ return H;
+}
+
+Error unloadLibrary(void *Handle) {
+ if (dlclose(Handle) != 0)
+ return make_error<StringError>((StringOutputStream()
+ << "error unloading " << Handle << ": "
+ << dlerror())
+ .str());
+ return Error::success();
+}
+
+std::vector<std::optional<void *>>
+lookupLibrarySymbols(void *Handle, const std::vector<std::string> &Names) {
+ std::vector<std::optional<void *>> Result;
+ Result.reserve(Names.size());
+ // Reset dlerror so we can distinguish "dlsym returned null because the
+ // symbol is present at address 0" from "dlsym returned null because the
+ // symbol isn't in the library" via per-iteration dlerror() checks.
+ dlerror();
+ for (const auto &Name : Names) {
+ auto LookupName = toDLSymName(Name);
+ if (!LookupName) {
+ Result.push_back(std::nullopt);
+ continue;
+ }
+
+ if (void *Addr = dlsym(Handle, *LookupName))
+ Result.push_back(Addr);
+ else if (dlerror() == nullptr)
+ Result.push_back(nullptr);
+ else
+ Result.push_back(std::nullopt);
+ }
+ return Result;
+}
+
+} // namespace orc_rt::sys
diff --git a/orc-rt/lib/bedrock/Unix/NativeMemoryAPIs.inc b/orc-rt/lib/bedrock/posix/Memory.cpp
similarity index 51%
rename from orc-rt/lib/bedrock/Unix/NativeMemoryAPIs.inc
rename to orc-rt/lib/bedrock/posix/Memory.cpp
index 43927e13b5ace..06028f129fc81 100644
--- a/orc-rt/lib/bedrock/Unix/NativeMemoryAPIs.inc
+++ b/orc-rt/lib/bedrock/posix/Memory.cpp
@@ -1,4 +1,4 @@
-//===- NativeMemoryAPIs.inc -------------------------------------*- C++ -*-===//
+//===- Memory.cpp - POSIX system memory operations -------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,46 +6,38 @@
//
//===----------------------------------------------------------------------===//
//
-// Generic wrappers for unix-style memory APIs (mmap, mprotect, etc.).
+// Implementation of orc-rt-internal/support/sys/Memory.h on POSIX
+// systems, in terms of mmap / munmap / mprotect.
//
//===----------------------------------------------------------------------===//
-#include "orc-rt/support/Error.h"
-#include "orc-rt/support/MemoryFlags.h"
+#include "orc-rt-internal/support/sys/Memory.h"
+
+#include "orc-rt-internal/support/sys/CacheControl.h"
#include <fcntl.h>
#include <string.h>
#include <sys/errno.h>
#include <sys/mman.h>
+namespace orc_rt::sys {
+
namespace {
-int toNativeProtFlags(orc_rt::MemProt MP) {
+int toNativeProtFlags(MemProt MP) {
int Prot = PROT_NONE;
- if ((MP & orc_rt::MemProt::Read) != orc_rt::MemProt::None)
+ if ((MP & MemProt::Read) != MemProt::None)
Prot |= PROT_READ;
- if ((MP & orc_rt::MemProt::Write) != orc_rt::MemProt::None)
+ if ((MP & MemProt::Write) != MemProt::None)
Prot |= PROT_WRITE;
- if ((MP & orc_rt::MemProt::Exec) != orc_rt::MemProt::None)
+ if ((MP & MemProt::Exec) != MemProt::None)
Prot |= PROT_EXEC;
return Prot;
}
-#if defined(__APPLE__)
-extern "C" void sys_icache_invalidate(const void *Addr, size_t Size);
-#else
-extern "C" void __clear_cache(void *Start, void *End);
-#endif
-
-static void invalidateInstructionCache(void *Addr, size_t Size) {
-#if defined(__APPLE__)
- sys_icache_invalidate(Addr, Size);
-#else
- __clear_cache(Addr, reinterpret_cast<char *>(Addr) + Size);
-#endif
-}
+} // namespace
-orc_rt::Expected<void *> hostOSMemoryReserve(size_t Size) {
+Expected<void *> reserveMemory(size_t Size) {
if (Size == 0)
return nullptr;
@@ -58,10 +50,10 @@ orc_rt::Expected<void *> hostOSMemoryReserve(size_t Size) {
MapFlags |= MAP_ANON;
#else // !defined(MAP_ANON)
// Fall back to /dev/zero for strict POSIX.
- fd = open("/dev/zero", O_RDWR);
- if (fd == -1) {
+ FD = open("/dev/zero", O_RDWR);
+ if (FD == -1) {
auto ErrNum = errno;
- return make_error<orc_rt::StringError>(
+ return make_error<StringError>(
std::string("Could not open /dev/zero for memory reserve: ") +
strerror(ErrNum));
}
@@ -70,34 +62,34 @@ orc_rt::Expected<void *> hostOSMemoryReserve(size_t Size) {
void *Addr = mmap(nullptr, Size, PROT_READ | PROT_WRITE, MapFlags, FD, 0);
if (Addr == MAP_FAILED) {
auto ErrNum = errno;
- return orc_rt::make_error<orc_rt::StringError>(
+ return make_error<StringError>(
std::string("mmap for memory reserve failed: ") + strerror(ErrNum));
}
return Addr;
}
-orc_rt::Error hostOSMemoryRelease(void *Base, size_t Size) {
+Error releaseMemory(void *Base, size_t Size) {
if (munmap(Base, Size) != 0) {
auto ErrNum = errno;
- return orc_rt::make_error<orc_rt::StringError>(
+ return make_error<StringError>(
std::string("munmap for memory release failed: ") + strerror(ErrNum));
}
- return orc_rt::Error::success();
+ return Error::success();
}
-orc_rt::Error hostOSMemoryProtect(void *Base, size_t Size, orc_rt::MemProt MP) {
+Error protectMemory(void *Base, size_t Size, MemProt MP) {
if (mprotect(Base, Size, toNativeProtFlags(MP)) != 0) {
auto ErrNum = errno;
- return orc_rt::make_error<orc_rt::StringError>(
+ return make_error<StringError>(
std::string("mprotect for memory finalize failed: ") +
strerror(ErrNum));
}
- if ((MP & orc_rt::MemProt::Exec) != orc_rt::MemProt::None)
- invalidateInstructionCache(Base, Size);
+ if ((MP & MemProt::Exec) != MemProt::None)
+ clear_icache(Base, Size);
- return orc_rt::Error::success();
+ return Error::success();
}
-} // namespace
+} // namespace orc_rt::sys
More information about the llvm-commits
mailing list