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 #ifndef jit_AutoWritableJitCode_h
8 #define jit_AutoWritableJitCode_h
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/ScopeExit.h"
13 #include "mozilla/TimeStamp.h"
17 #include "jit/ExecutableAllocator.h"
18 #include "jit/JitCode.h"
19 #include "jit/JitOptions.h"
20 #include "jit/ProcessExecutableMemory.h"
21 #include "vm/JSContext.h"
23 #include "vm/Runtime.h"
27 // This class ensures JIT code is executable on its destruction. Creators
28 // must call makeWritable(), and not attempt to write to the buffer if it fails.
30 // AutoWritableJitCodeFallible may only fail to make code writable; it cannot
31 // fail to make JIT code executable (because the creating code has no chance to
32 // recover from a failed destructor).
33 class MOZ_RAII AutoWritableJitCodeFallible
{
37 AutoMarkJitCodeWritableForThread writableForThread_
;
40 AutoWritableJitCodeFallible(JSRuntime
* rt
, void* addr
, size_t size
)
41 : rt_(rt
), addr_(addr
), size_(size
) {
42 rt_
->toggleAutoWritableJitCodeActive(true);
45 AutoWritableJitCodeFallible(void* addr
, size_t size
)
46 : AutoWritableJitCodeFallible(TlsContext
.get()->runtime(), addr
, size
) {}
48 explicit AutoWritableJitCodeFallible(JitCode
* code
)
49 : AutoWritableJitCodeFallible(code
->runtimeFromMainThread(), code
->raw(),
50 code
->bufferSize()) {}
52 [[nodiscard
]] bool makeWritable() {
53 return ExecutableAllocator::makeWritable(addr_
, size_
);
56 ~AutoWritableJitCodeFallible() {
57 // Taking TimeStamps frequently can be expensive, and there's no point
58 // measuring this if write protection is disabled.
59 const bool measuringTime
= JitOptions
.writeProtectCode
;
60 const mozilla::TimeStamp startTime
=
61 measuringTime
? mozilla::TimeStamp::Now() : mozilla::TimeStamp();
62 auto timer
= mozilla::MakeScopeExit([&] {
64 if (Realm
* realm
= rt_
->mainContextFromOwnThread()->realm()) {
65 realm
->timers
.protectTime
+= mozilla::TimeStamp::Now() - startTime
;
70 if (!ExecutableAllocator::makeExecutableAndFlushICache(addr_
, size_
)) {
73 rt_
->toggleAutoWritableJitCodeActive(false);
77 // Infallible variant of AutoWritableJitCodeFallible, ensures writable during
79 class MOZ_RAII AutoWritableJitCode
: private AutoWritableJitCodeFallible
{
81 AutoWritableJitCode(JSRuntime
* rt
, void* addr
, size_t size
)
82 : AutoWritableJitCodeFallible(rt
, addr
, size
) {
83 AutoEnterOOMUnsafeRegion oomUnsafe
;
84 if (!makeWritable()) {
85 oomUnsafe
.crash("Failed to mmap. Likely no mappings available.");
89 AutoWritableJitCode(void* addr
, size_t size
)
90 : AutoWritableJitCode(TlsContext
.get()->runtime(), addr
, size
) {}
92 explicit AutoWritableJitCode(JitCode
* code
)
93 : AutoWritableJitCode(code
->runtimeFromMainThread(), code
->raw(),
94 code
->bufferSize()) {}
97 } // namespace js::jit
99 #endif /* jit_AutoWritableJitCode_h */