[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