v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
code-memory-access-inl.h
Go to the documentation of this file.
1// Copyright 2022 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_COMMON_CODE_MEMORY_ACCESS_INL_H_
6#define V8_COMMON_CODE_MEMORY_ACCESS_INL_H_
7
9// Include the non-inl header before the rest of the headers.
10
11#include "src/flags/flags.h"
14#include "src/objects/tagged.h"
15#if V8_HAS_PKU_JIT_WRITE_PROTECT
17#endif
18#if V8_HAS_PTHREAD_JIT_WRITE_PROTECT
20#endif
21#if V8_HAS_BECORE_JIT_WRITE_PROTECT
22#include <BrowserEngineCore/BEMemory.h>
23#endif
24
25namespace v8 {
26namespace internal {
27
29 if (!v8_flags.jitless) {
31 }
32}
33
39
41#ifdef DEBUG
42 if (enforce_write_api_ && page_ref_.has_value()) {
43 // We disabled RWX write access for debugging. But we'll need it in the
44 // destructor again to release the jit page reference.
45 write_scope_.emplace("~WritableJitAllocation");
46 }
47#endif
48}
49
51 Address addr, size_t size, ThreadIsolation::JitAllocationType type,
52 JitAllocationSource source, bool enforce_write_api)
53 : address_(addr),
54 // The order of these is important. We need to create the write scope
55 // before we lookup the Jit page, since the latter will take a mutex in
56 // protected memory.
57 write_scope_("WritableJitAllocation"),
58 page_ref_(ThreadIsolation::LookupJitPage(addr, size)),
60 ? page_ref_->RegisterAllocation(addr, size, type)
61 : page_ref_->LookupAllocation(addr, size, type)),
62 enforce_write_api_(enforce_write_api) {
63#ifdef DEBUG
65 // Reset the write scope for debugging. We'll create fine-grained scopes in
66 // all Write functions of this class instead.
67 write_scope_.reset();
68 }
69#else
70 // Suppress -Wunused-private-field warning.
72#endif
73}
74
76 Address addr, size_t size, ThreadIsolation::JitAllocationType type,
77 bool enforce_write_api)
78 : address_(addr),
79 allocation_(size, type),
80 enforce_write_api_(enforce_write_api) {}
81
82// static
87
88std::optional<RwxMemoryWriteScope>
90#ifdef DEBUG
92 return std::optional<RwxMemoryWriteScope>("WriteScopeForApiEnforcement");
93 }
94#endif
95 return {};
96}
97
98#ifdef V8_ENABLE_WEBASSEMBLY
99
100WritableJumpTablePair::WritableJumpTablePair(Address jump_table_address,
101 size_t jump_table_size,
102 Address far_jump_table_address,
103 size_t far_jump_table_size)
104 : writable_jump_table_(jump_table_address, jump_table_size,
105 ThreadIsolation::JitAllocationType::kWasmJumpTable,
106 true),
107 writable_far_jump_table_(
108 far_jump_table_address, far_jump_table_size,
109 ThreadIsolation::JitAllocationType::kWasmFarJumpTable, true),
110 write_scope_("WritableJumpTablePair"),
111 // Always split the pages since we are not guaranteed that the jump table
112 // and far jump table are on the same JitPage.
113 jump_table_pages_(ThreadIsolation::SplitJitPages(
114 far_jump_table_address, far_jump_table_size, jump_table_address,
115 jump_table_size)) {
116 CHECK(jump_table_pages_.value().second.Contains(
117 jump_table_address, jump_table_size,
119 CHECK(jump_table_pages_.value().first.Contains(
120 far_jump_table_address, far_jump_table_size,
122
123#ifdef DEBUG
124 // Reset the write scope for debugging. We'll create fine-grained scopes in
125 // all Write functions of this class instead.
126 write_scope_.SetExecutable();
127#endif
128}
129
130#endif
131
132template <typename T, size_t offset>
134 std::optional<RwxMemoryWriteScope> write_scope =
136 // This assert is no strict requirement, it just guards against
137 // non-implemented functionality.
138 static_assert(!is_taggable_v<T>);
139
140 if constexpr (offset == HeapObject::kMapOffset) {
143 } else {
145 }
146}
147
148template <typename T, size_t offset>
150 std::optional<RwxMemoryWriteScope> write_scope =
152 // These asserts are no strict requirements, they just guard against
153 // non-implemented functionality.
154 static_assert(offset != HeapObject::kMapOffset);
155
157 value);
158}
159
160template <typename T, size_t offset>
172
173template <typename T, size_t offset>
182
183template <typename T, size_t offset>
192
193template <typename T>
195 RelaxedStoreTag tag) {
196 CHECK_EQ(allocation_.Type(),
198 size_t offset = address - address_;
199 Tagged<T> tagged(value);
200 switch (offset) {
201 case InstructionStream::kCodeOffset:
203 tag);
204 break;
205 case InstructionStream::kRelocationInfoOffset:
207 InstructionStream::kRelocationInfoOffset>(
208 tagged, tag);
209 break;
210 default:
211 UNREACHABLE();
212 }
213}
214
215template <typename T>
217 T value) {
218 std::optional<RwxMemoryWriteScope> write_scope =
223}
224
225template <typename T>
227 std::optional<RwxMemoryWriteScope> write_scope =
232}
233
234template <typename T>
237 std::optional<RwxMemoryWriteScope> write_scope =
241 reinterpret_cast<std::atomic<T>*>(address)->store(value,
242 std::memory_order_relaxed);
243}
244
245void WritableJitAllocation::CopyCode(size_t dst_offset, const uint8_t* src,
246 size_t num_bytes) {
247 std::optional<RwxMemoryWriteScope> write_scope =
249 CopyBytes(reinterpret_cast<uint8_t*>(address_ + dst_offset), src, num_bytes);
250}
251
252void WritableJitAllocation::CopyData(size_t dst_offset, const uint8_t* src,
253 size_t num_bytes) {
254 std::optional<RwxMemoryWriteScope> write_scope =
256 CopyBytes(reinterpret_cast<uint8_t*>(address_ + dst_offset), src, num_bytes);
257}
258
260 std::optional<RwxMemoryWriteScope> write_scope =
262 memset(reinterpret_cast<void*>(address_ + offset), 0, len);
263}
264
266
268 : write_scope_("WritableJitPage"),
269 page_ref_(ThreadIsolation::LookupJitPage(addr, size)) {}
270
272 Address addr) {
273 auto pair = page_ref_.AllocationContaining(addr);
274 return WritableJitAllocation(pair.first, pair.second.Size(),
275 pair.second.Type(), false);
276}
277
279 size_t size) {
280 page_ref_.UnregisterRange(addr, size);
281 return WritableFreeSpace(addr, size, true);
282}
283
285
286// static
289 return WritableFreeSpace(addr, size, false);
290}
291
293 bool executable)
294 : address_(addr), size_(static_cast<int>(size)), executable_(executable) {}
295
296template <typename T, size_t offset>
298 RelaxedStoreTag) const {
300 // TODO(v8:13355): add validation before the write.
301 if constexpr (offset == HeapObject::kMapOffset) {
303 } else {
305 }
306}
307
308#if V8_HAS_PTHREAD_JIT_WRITE_PROTECT
309
310// static
311bool RwxMemoryWriteScope::IsSupported() { return true; }
312
313// static
314void RwxMemoryWriteScope::SetWritable() { base::SetJitWriteProtected(0); }
315
316// static
317void RwxMemoryWriteScope::SetExecutable() { base::SetJitWriteProtected(1); }
318
319#elif V8_HAS_BECORE_JIT_WRITE_PROTECT
320
321// static
323 return be_memory_inline_jit_restrict_with_witness_supported() != 0;
324}
325
326// static
328 be_memory_inline_jit_restrict_rwx_to_rw_with_witness();
329}
330
331// static
333 be_memory_inline_jit_restrict_rwx_to_rx_with_witness();
334}
335
336#elif V8_HAS_PKU_JIT_WRITE_PROTECT
337// static
339 static_assert(base::MemoryProtectionKey::kNoMemoryProtectionKey == -1);
340 DCHECK(ThreadIsolation::initialized());
341 return ThreadIsolation::PkeyIsAvailable();
342}
343
344// static
346 DCHECK(ThreadIsolation::initialized());
347 if (!IsSupported()) return;
348
349 DCHECK_NE(
350 base::MemoryProtectionKey::GetKeyPermission(ThreadIsolation::pkey()),
351 base::MemoryProtectionKey::kNoRestrictions);
352
353 base::MemoryProtectionKey::SetPermissionsForKey(
354 ThreadIsolation::pkey(), base::MemoryProtectionKey::kNoRestrictions);
355}
356
357// static
359 DCHECK(ThreadIsolation::initialized());
360 if (!IsSupported()) return;
361
362 DCHECK_EQ(
363 base::MemoryProtectionKey::GetKeyPermission(ThreadIsolation::pkey()),
364 base::MemoryProtectionKey::kNoRestrictions);
365
366 base::MemoryProtectionKey::SetPermissionsForKey(
367 ThreadIsolation::pkey(), base::MemoryProtectionKey::kDisableWrite);
368}
369
370#else // !V8_HAS_PTHREAD_JIT_WRITE_PROTECT && !V8_TRY_USE_PKU_JIT_WRITE_PROTECT
371
372// static
373bool RwxMemoryWriteScope::IsSupported() { return false; }
374
375// static
377
378// static
380
381#endif // V8_HAS_PTHREAD_JIT_WRITE_PROTECT
382
383} // namespace internal
384} // namespace v8
385
386#endif // V8_COMMON_CODE_MEMORY_ACCESS_INL_H_
#define T
static Tagged< HeapObject > FromAddress(Address address)
static constexpr int kMapOffset
V8_INLINE RwxMemoryWriteScope(const char *comment)
static void Release_Store(Tagged< HeapObject > host, PtrType value)
static void Relaxed_Store(Tagged< HeapObject > host, PtrType value)
static void Relaxed_Store_Map_Word(Tagged< HeapObject > host, PtrType value)
void UnregisterRange(base::Address addr, size_t size)
std::pair< base::Address, JitAllocation & > AllocationContaining(base::Address addr)
V8_INLINE void WriteHeaderSlot(Tagged< T > value, RelaxedStoreTag) const
WritableFreeSpace(const WritableFreeSpace &)=delete
static V8_INLINE WritableFreeSpace ForNonExecutableMemory(base::Address addr, size_t size)
static V8_INLINE WritableJitAllocation ForNonExecutableMemory(Address addr, size_t size, ThreadIsolation::JitAllocationType type)
V8_INLINE void WriteUnalignedValue(Address address, T value)
const ThreadIsolation::JitAllocation allocation_
V8_INLINE void CopyCode(size_t dst_offset, const uint8_t *src, size_t num_bytes)
V8_INLINE void WriteValue(Address address, T value)
std::optional< ThreadIsolation::JitPageReference > page_ref_
V8_INLINE void WriteHeaderSlot(T value)
V8_INLINE void ClearBytes(size_t offset, size_t len)
V8_INLINE void WriteProtectedPointerHeaderSlot(Tagged< T > value, ReleaseStoreTag)
WritableJitAllocation(const WritableJitAllocation &)=delete
V8_INLINE void CopyData(size_t dst_offset, const uint8_t *src, size_t num_bytes)
V8_INLINE std::optional< RwxMemoryWriteScope > WriteScopeForApiEnforcement() const
std::optional< RwxMemoryWriteScope > write_scope_
V8_INLINE WritableJitAllocation LookupAllocationContaining(Address addr)
V8_INLINE WritableFreeSpace FreeRange(Address addr, size_t size)
V8_INLINE WritableJitPage(Address addr, size_t size)
ThreadIsolation::JitPageReference page_ref_
const int size_
Definition assembler.cc:132
const AllocationType allocation_
int32_t offset
T & Memory(Address addr)
Definition memory.h:18
uintptr_t Address
Definition memory.h:13
static void WriteUnalignedValue(Address p, V value)
Definition memory.h:41
void CopyBytes(T *dst, const T *src, size_t num_bytes)
Definition memcopy.h:261
static void WriteMaybeUnalignedValue(Address p, V value)
Definition ptr-compr.h:225
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats store(v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE)) DEFINE_GENERIC_IMPLICATION(trace_gc_object_stats
static constexpr bool is_taggable_v
Definition tagged.h:316
V8_EXPORT_PRIVATE FlagValues v8_flags
return value
Definition map-inl.h:893
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_INLINE
Definition v8config.h:500