Bug 1890513: Directly invoke variadic native functions. r=jandem
[gecko.git] / js / src / jit / FlushICache.cpp
blob1e2ec69272fe884f61b0e529887ed633a900bf3d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jit/FlushICache.h"
9 #ifdef JS_CODEGEN_ARM64
10 # include "jit/arm64/vixl/MozCachingDecoder.h"
11 # include "jit/arm64/vixl/Simulator-vixl.h"
12 #endif
14 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
16 # ifdef __linux__
17 # include <linux/version.h>
18 # define LINUX_HAS_MEMBARRIER (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0))
19 # else
20 # define LINUX_HAS_MEMBARRIER 0
21 # endif
23 # if LINUX_HAS_MEMBARRIER || defined(__android__)
24 # include <string.h>
26 # if LINUX_HAS_MEMBARRIER
27 # include <linux/membarrier.h>
28 # include <sys/syscall.h>
29 # include <sys/utsname.h>
30 # include <unistd.h>
31 # elif defined(__android__)
32 # include <sys/syscall.h>
33 # include <unistd.h>
34 # else
35 # error "Missing platform-specific declarations for membarrier syscall!"
36 # endif // __linux__ / ANDROID
38 static int membarrier(int cmd, int flags) {
39 return syscall(__NR_membarrier, cmd, flags);
42 // These definitions come from the Linux kernel source, for kernels before 4.16
43 // which didn't have access to these membarrier commands.
44 # ifndef MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE
45 # define MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE (1 << 5)
46 # endif
48 # ifndef MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE
49 # define MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE (1 << 6)
50 # endif
51 # endif // LINUX_HAS_MEMBARRIER || defined(__android__)
53 using namespace js;
54 using namespace js::jit;
56 namespace js {
57 namespace jit {
59 bool CanFlushExecutionContextForAllThreads() {
60 # if (LINUX_HAS_MEMBARRIER || defined(__android__))
61 // On linux, check the kernel supports membarrier(2), that is, it's a kernel
62 // above Linux 4.16 included.
64 // Note: this code has been extracted (August 2020) from
65 // https://android.googlesource.com/platform/art/+/58520dfba31d6eeef75f5babff15e09aa28e5db8/libartbase/base/membarrier.cc#50
66 static constexpr int kRequiredMajor = 4;
67 static constexpr int kRequiredMinor = 16;
69 static bool computed = false;
70 static bool kernelHasMembarrier = false;
72 if (computed) {
73 return kernelHasMembarrier;
76 struct utsname uts;
77 int major, minor;
78 kernelHasMembarrier = uname(&uts) == 0 && strcmp(uts.sysname, "Linux") == 0 &&
79 sscanf(uts.release, "%d.%d", &major, &minor) == 2 &&
80 major >= kRequiredMajor &&
81 (major != kRequiredMajor || minor >= kRequiredMinor);
83 // As a test bed, try to run the syscall with the command registering the
84 // intent to use the actual membarrier we'll want to carry out later.
86 // IMPORTANT: This is required or else running the membarrier later won't
87 // actually interrupt the threads in this process.
88 if (kernelHasMembarrier &&
89 membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, 0) != 0) {
90 kernelHasMembarrier = false;
93 computed = true;
94 return kernelHasMembarrier;
95 # else
96 // On other platforms, we assume that the syscall for flushing the icache
97 // will flush the execution context for other cores.
98 return true;
99 # endif
102 void FlushExecutionContextForAllThreads() {
103 // Callers must check that this operation is available.
104 MOZ_RELEASE_ASSERT(CanFlushExecutionContextForAllThreads());
106 # if defined(JS_SIMULATOR_ARM64) && defined(JS_CACHE_SIMULATOR_ARM64)
107 // Emulate what the real hardware would do by emitting a membarrier that'll
108 // interrupt and flush the execution context of all threads.
109 using js::jit::SimulatorProcess;
110 js::jit::AutoLockSimulatorCache alsc;
111 SimulatorProcess::membarrier();
112 # elif (LINUX_HAS_MEMBARRIER || defined(__android__))
113 // The caller has checked this can be performed, which will have registered
114 // this process to receive the membarrier. See above.
116 // membarrier will trigger an inter-processor-interrupt on any active threads
117 // of this process. This is an execution context synchronization event
118 // equivalent to running an `isb` instruction.
119 if (membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, 0) != 0) {
120 // Better safe than sorry.
121 MOZ_CRASH("membarrier can't be executed");
123 # else
124 // On other platforms, we assume that the syscall for flushing the icache
125 // will flush the execution context for other cores.
126 # endif
129 } // namespace jit
130 } // namespace js
132 #endif