Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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
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