summaryrefslogtreecommitdiffstats
path: root/js/src/jit/FlushICache.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/jit/FlushICache.cpp
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit/FlushICache.cpp')
-rw-r--r--js/src/jit/FlushICache.cpp132
1 files changed, 132 insertions, 0 deletions
diff --git a/js/src/jit/FlushICache.cpp b/js/src/jit/FlushICache.cpp
new file mode 100644
index 0000000000..1e2ec69272
--- /dev/null
+++ b/js/src/jit/FlushICache.cpp
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jit/FlushICache.h"
+
+#ifdef JS_CODEGEN_ARM64
+# include "jit/arm64/vixl/MozCachingDecoder.h"
+# include "jit/arm64/vixl/Simulator-vixl.h"
+#endif
+
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
+
+# ifdef __linux__
+# include <linux/version.h>
+# define LINUX_HAS_MEMBARRIER (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0))
+# else
+# define LINUX_HAS_MEMBARRIER 0
+# endif
+
+# if LINUX_HAS_MEMBARRIER || defined(__android__)
+# include <string.h>
+
+# if LINUX_HAS_MEMBARRIER
+# include <linux/membarrier.h>
+# include <sys/syscall.h>
+# include <sys/utsname.h>
+# include <unistd.h>
+# elif defined(__android__)
+# include <sys/syscall.h>
+# include <unistd.h>
+# else
+# error "Missing platform-specific declarations for membarrier syscall!"
+# endif // __linux__ / ANDROID
+
+static int membarrier(int cmd, int flags) {
+ return syscall(__NR_membarrier, cmd, flags);
+}
+
+// These definitions come from the Linux kernel source, for kernels before 4.16
+// which didn't have access to these membarrier commands.
+# ifndef MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE
+# define MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE (1 << 5)
+# endif
+
+# ifndef MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE
+# define MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE (1 << 6)
+# endif
+# endif // LINUX_HAS_MEMBARRIER || defined(__android__)
+
+using namespace js;
+using namespace js::jit;
+
+namespace js {
+namespace jit {
+
+bool CanFlushExecutionContextForAllThreads() {
+# if (LINUX_HAS_MEMBARRIER || defined(__android__))
+ // On linux, check the kernel supports membarrier(2), that is, it's a kernel
+ // above Linux 4.16 included.
+ //
+ // Note: this code has been extracted (August 2020) from
+ // https://android.googlesource.com/platform/art/+/58520dfba31d6eeef75f5babff15e09aa28e5db8/libartbase/base/membarrier.cc#50
+ static constexpr int kRequiredMajor = 4;
+ static constexpr int kRequiredMinor = 16;
+
+ static bool computed = false;
+ static bool kernelHasMembarrier = false;
+
+ if (computed) {
+ return kernelHasMembarrier;
+ }
+
+ struct utsname uts;
+ int major, minor;
+ kernelHasMembarrier = uname(&uts) == 0 && strcmp(uts.sysname, "Linux") == 0 &&
+ sscanf(uts.release, "%d.%d", &major, &minor) == 2 &&
+ major >= kRequiredMajor &&
+ (major != kRequiredMajor || minor >= kRequiredMinor);
+
+ // As a test bed, try to run the syscall with the command registering the
+ // intent to use the actual membarrier we'll want to carry out later.
+ //
+ // IMPORTANT: This is required or else running the membarrier later won't
+ // actually interrupt the threads in this process.
+ if (kernelHasMembarrier &&
+ membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, 0) != 0) {
+ kernelHasMembarrier = false;
+ }
+
+ computed = true;
+ return kernelHasMembarrier;
+# else
+ // On other platforms, we assume that the syscall for flushing the icache
+ // will flush the execution context for other cores.
+ return true;
+# endif
+}
+
+void FlushExecutionContextForAllThreads() {
+ // Callers must check that this operation is available.
+ MOZ_RELEASE_ASSERT(CanFlushExecutionContextForAllThreads());
+
+# if defined(JS_SIMULATOR_ARM64) && defined(JS_CACHE_SIMULATOR_ARM64)
+ // Emulate what the real hardware would do by emitting a membarrier that'll
+ // interrupt and flush the execution context of all threads.
+ using js::jit::SimulatorProcess;
+ js::jit::AutoLockSimulatorCache alsc;
+ SimulatorProcess::membarrier();
+# elif (LINUX_HAS_MEMBARRIER || defined(__android__))
+ // The caller has checked this can be performed, which will have registered
+ // this process to receive the membarrier. See above.
+ //
+ // membarrier will trigger an inter-processor-interrupt on any active threads
+ // of this process. This is an execution context synchronization event
+ // equivalent to running an `isb` instruction.
+ if (membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, 0) != 0) {
+ // Better safe than sorry.
+ MOZ_CRASH("membarrier can't be executed");
+ }
+# else
+ // On other platforms, we assume that the syscall for flushing the icache
+ // will flush the execution context for other cores.
+# endif
+}
+
+} // namespace jit
+} // namespace js
+
+#endif