v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
ptr-compr-inl.h
Go to the documentation of this file.
1// Copyright 2018 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_PTR_COMPR_INL_H_
6#define V8_COMMON_PTR_COMPR_INL_H_
7
9// Include the non-inl header before the rest of the headers.
10
11#include "include/v8-internal.h"
14
15#ifdef V8_ENABLE_SANDBOX
16#include "src/sandbox/sandbox.h"
17#endif // V8_ENABLE_SANDBOX
18
19namespace v8 {
20namespace internal {
21
22#ifdef V8_COMPRESS_POINTERS
23
24PtrComprCageBase::PtrComprCageBase(const Isolate* isolate)
25 : address_(isolate->cage_base()) {}
26PtrComprCageBase::PtrComprCageBase(const LocalIsolate* isolate)
27 : address_(isolate->cage_base()) {}
28
29//
30// V8HeapCompressionSchemeImpl
31//
32
33constexpr Address kPtrComprCageBaseMask = ~(kPtrComprCageBaseAlignment - 1);
34
35// static
36template <typename Cage>
37constexpr Address V8HeapCompressionSchemeImpl<Cage>::GetPtrComprCageBaseAddress(
38 Address on_heap_addr) {
39 return RoundDown<kPtrComprCageBaseAlignment>(on_heap_addr);
40}
41
42// static
43template <typename Cage>
44Address V8HeapCompressionSchemeImpl<Cage>::GetPtrComprCageBaseAddress(
45 PtrComprCageBase cage_base) {
46 Address base = cage_base.address();
47 V8_ASSUME((base & kPtrComprCageBaseMask) == base);
48 base = reinterpret_cast<Address>(V8_ASSUME_ALIGNED(
49 reinterpret_cast<void*>(base), kPtrComprCageBaseAlignment));
50 return base;
51}
52
53// static
54template <typename Cage>
55void V8HeapCompressionSchemeImpl<Cage>::InitBase(Address base) {
56 CHECK_EQ(base, GetPtrComprCageBaseAddress(base));
57#if defined(USING_V8_SHARED_PRIVATE) && \
58 defined(V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES)
59 Cage::set_base_non_inlined(base);
60#else
61 Cage::base_ = base;
62#endif
63}
64
65// static
66template <typename Cage>
67Address V8HeapCompressionSchemeImpl<Cage>::base() {
68#if defined(USING_V8_SHARED_PRIVATE) && \
69 defined(V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES)
70 Address base = Cage::base_non_inlined();
71#else
72 Address base = Cage::base_;
73#endif
74 // V8_ASSUME_ALIGNED is often not preserved across ptr-to-int casts (i.e. when
75 // casting to an Address). To increase our chances we additionally encode the
76 // same information in this V8_ASSUME.
77 V8_ASSUME((base & kPtrComprCageBaseMask) == base);
78 return reinterpret_cast<Address>(V8_ASSUME_ALIGNED(
79 reinterpret_cast<void*>(base), kPtrComprCageBaseAlignment));
80}
81
82// static
83template <typename Cage>
84Tagged_t V8HeapCompressionSchemeImpl<Cage>::CompressObject(Address tagged) {
85 // This is used to help clang produce better code. Values which could be
86 // invalid pointers need to be compressed with CompressAny.
87#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
89 (tagged & kPtrComprCageBaseMask) == base());
90#endif
91 return static_cast<Tagged_t>(tagged);
92}
93
94// static
95template <typename Cage>
96constexpr Tagged_t V8HeapCompressionSchemeImpl<Cage>::CompressAny(
97 Address tagged) {
98 return static_cast<Tagged_t>(tagged);
99}
100
101// static
102template <typename Cage>
103Address V8HeapCompressionSchemeImpl<Cage>::DecompressTaggedSigned(
104 Tagged_t raw_value) {
105 // For runtime code the upper 32-bits of the Smi value do not matter.
106 return static_cast<Address>(raw_value);
107}
108
109// static
110template <typename Cage>
111template <typename TOnHeapAddress>
112Address V8HeapCompressionSchemeImpl<Cage>::DecompressTagged(
113 TOnHeapAddress on_heap_addr, Tagged_t raw_value) {
114#ifdef V8_COMPRESS_POINTERS
115 Address cage_base = base();
116#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
117 DCHECK_WITH_MSG(cage_base != kNullAddress,
118 "V8HeapCompressionSchemeImpl::base is not initialized for "
119 "current thread");
120#endif // V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
121#else
122 Address cage_base = GetPtrComprCageBaseAddress(on_heap_addr);
123#endif // V8_COMPRESS_POINTERS
124 Address result = cage_base + static_cast<Address>(raw_value);
125 V8_ASSUME(static_cast<uint32_t>(result) == raw_value);
126 return result;
127}
128
129// static
130template <typename Cage>
131template <typename ProcessPointerCallback>
132void V8HeapCompressionSchemeImpl<Cage>::ProcessIntermediatePointers(
133 PtrComprCageBase cage_base, Address raw_value,
134 ProcessPointerCallback callback) {
135 // If pointer compression is enabled, we may have random compressed pointers
136 // on the stack that may be used for subsequent operations.
137 // Extract, decompress and trace both halfwords.
138 Address decompressed_low =
139 V8HeapCompressionSchemeImpl<Cage>::DecompressTagged(
140 cage_base, static_cast<Tagged_t>(raw_value));
141 callback(decompressed_low);
142 Address decompressed_high =
143 V8HeapCompressionSchemeImpl<Cage>::DecompressTagged(
144 cage_base,
145 static_cast<Tagged_t>(raw_value >> (sizeof(Tagged_t) * CHAR_BIT)));
146 callback(decompressed_high);
147}
148
149#ifdef V8_EXTERNAL_CODE_SPACE
150
151//
152// ExternalCodeCompressionScheme
153//
154
155constexpr Address kMinExpectedOSPageSizeMask = ~(kMinExpectedOSPageSize - 1);
156
157// static
158Address ExternalCodeCompressionScheme::PrepareCageBaseAddress(
159 Address on_heap_addr) {
160 return RoundDown<kMinExpectedOSPageSize>(on_heap_addr);
161}
162
163// static
164Address ExternalCodeCompressionScheme::GetPtrComprCageBaseAddress(
165 PtrComprCageBase cage_base) {
166 Address base = cage_base.address();
167 V8_ASSUME((base & kMinExpectedOSPageSizeMask) == base);
168 base = reinterpret_cast<Address>(
169 V8_ASSUME_ALIGNED(reinterpret_cast<void*>(base), kMinExpectedOSPageSize));
170 return base;
171}
172
173// static
174void ExternalCodeCompressionScheme::InitBase(Address base) {
175 CHECK_EQ(base, PrepareCageBaseAddress(base));
176#if defined(USING_V8_SHARED_PRIVATE) && \
177 defined(V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES)
178 set_base_non_inlined(base);
179#else
180 base_ = base;
181#endif
182}
183
184// static
185V8_CONST Address ExternalCodeCompressionScheme::base() {
186#if defined(USING_V8_SHARED_PRIVATE) && \
187 defined(V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES)
188 Address base = base_non_inlined();
189#else
191#endif
192 // V8_ASSUME_ALIGNED is often not preserved across ptr-to-int casts (i.e. when
193 // casting to an Address). To increase our chances we additionally encode the
194 // same information in this V8_ASSUME.
195 V8_ASSUME((base & kMinExpectedOSPageSizeMask) == base);
196 return reinterpret_cast<Address>(
197 V8_ASSUME_ALIGNED(reinterpret_cast<void*>(base), kMinExpectedOSPageSize));
198}
199
200// static
201Tagged_t ExternalCodeCompressionScheme::CompressObject(Address tagged) {
202 // Sanity check - the tagged value should belong to this cage.
203#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
205 !HAS_SMI_TAG(tagged),
206 (base() <= tagged) && (tagged < base() + kPtrComprCageReservationSize));
207#endif
208 return static_cast<Tagged_t>(tagged);
209}
210
211// static
212constexpr Tagged_t ExternalCodeCompressionScheme::CompressAny(Address tagged) {
213 return static_cast<Tagged_t>(tagged);
214}
215
216// static
217Address ExternalCodeCompressionScheme::DecompressTaggedSigned(
218 Tagged_t raw_value) {
219 // For runtime code the upper 32-bits of the Smi value do not matter.
220 return static_cast<Address>(raw_value);
221}
222
223// static
224template <typename TOnHeapAddress>
225Address ExternalCodeCompressionScheme::DecompressTagged(
226 TOnHeapAddress on_heap_addr, Tagged_t raw_value) {
227#ifdef V8_ENABLE_CONSERVATIVE_STACK_SCANNING
228 // During conservative stack scanning, if we are trying to decompress a value
229 // that looks like a SMI (i.e., it's not tagged), we always need to add the
230 // cage base.
231#else
232 // Avoid complex decompression code for Smis.
233 if (HAS_SMI_TAG(raw_value)) return DecompressTaggedSigned(raw_value);
234#endif
235
236#ifdef V8_COMPRESS_POINTERS
237 Address cage_base = base();
238#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
239 DCHECK_WITH_MSG(cage_base != kNullAddress,
240 "ExternalCodeCompressionScheme::base is not initialized for "
241 "current thread");
242#endif // V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
243#else
244 Address cage_base = GetPtrComprCageBaseAddress(on_heap_addr);
245#endif // V8_COMPRESS_POINTERS
246 V8_ASSUME((cage_base & kMinExpectedOSPageSizeMask) == cage_base);
247
248 Address diff = static_cast<Address>(static_cast<uint32_t>(raw_value)) -
249 static_cast<Address>(static_cast<uint32_t>(cage_base));
250 // The cage base value was chosen such that it's less or equal than any
251 // pointer in the cage, thus if we got a negative diff then it means that
252 // the decompressed value is off by 4GB.
253 if (static_cast<intptr_t>(diff) < 0) {
254 diff += size_t{4} * GB;
255 }
256 DCHECK(is_uint32(diff));
257 Address result = cage_base + diff;
258 DCHECK_EQ(static_cast<uint32_t>(result), raw_value);
259 return result;
260}
261
262// static
263template <typename ProcessPointerCallback>
264void ExternalCodeCompressionScheme::ProcessIntermediatePointers(
265 PtrComprCageBase cage_base, Address raw_value,
266 ProcessPointerCallback callback) {
267 // If pointer compression is enabled, we may have random compressed pointers
268 // on the stack that may be used for subsequent operations.
269 // Extract, decompress and trace both halfwords.
270 Address decompressed_low = ExternalCodeCompressionScheme::DecompressTagged(
271 cage_base, static_cast<Tagged_t>(raw_value));
272 callback(decompressed_low);
273 Address decompressed_high = ExternalCodeCompressionScheme::DecompressTagged(
274 cage_base,
275 static_cast<Tagged_t>(raw_value >> (sizeof(Tagged_t) * CHAR_BIT)));
276 callback(decompressed_high);
277}
278
279#endif // V8_EXTERNAL_CODE_SPACE
280
281//
282// Misc functions.
283//
284
285V8_INLINE PtrComprCageBase
287 return PtrComprCageBase(
288 V8HeapCompressionScheme::GetPtrComprCageBaseAddress(address));
289}
290
291// Load the main pointer compression cage base.
292V8_INLINE PtrComprCageBase GetPtrComprCageBase() {
293 return PtrComprCageBase(V8HeapCompressionScheme::base());
294}
295
296#else
297
298//
299// V8HeapCompressionSchemeImpl
300//
301
302// static
303template <typename Cage>
305 Address on_heap_addr) {
306 UNREACHABLE();
307 return {};
308}
309
310// static
311template <typename Cage>
315
316// static
317template <typename Cage>
319 Address tagged) {
320 UNREACHABLE();
321 return {};
322}
323
324// static
325template <typename Cage>
330
331// static
332template <typename Cage>
333template <typename TOnHeapAddress>
335 TOnHeapAddress on_heap_addr, Tagged_t raw_value) {
336 UNREACHABLE();
337}
338
339// static
340template <typename Cage>
341template <typename ProcessPointerCallback>
343 PtrComprCageBase cage_base, Address raw_value,
344 ProcessPointerCallback callback) {
345 UNREACHABLE();
346}
347
348//
349// Misc functions.
350//
351
353 Address address) {
354 return PtrComprCageBase();
355}
356
358
359#endif // V8_COMPRESS_POINTERS
360
364
365#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
366
367PtrComprCageAccessScope::PtrComprCageAccessScope(Isolate* isolate)
368 : cage_base_(V8HeapCompressionScheme::base()),
369#ifdef V8_EXTERNAL_CODE_SPACE
370 code_cage_base_(ExternalCodeCompressionScheme::base()),
371#endif // V8_EXTERNAL_CODE_SPACE
372 saved_current_isolate_group_(IsolateGroup::current())
373#ifdef V8_ENABLE_SANDBOX
374 ,
375 saved_current_sandbox_(Sandbox::current())
376#endif // V8_ENABLE_SANDBOX
377{
378 V8HeapCompressionScheme::InitBase(isolate->cage_base());
379#ifdef V8_EXTERNAL_CODE_SPACE
380 ExternalCodeCompressionScheme::InitBase(isolate->code_cage_base());
381#endif // V8_EXTERNAL_CODE_SPACE
382 IsolateGroup::set_current(isolate->isolate_group());
383#ifdef V8_ENABLE_SANDBOX
384 Sandbox::set_current(isolate->isolate_group()->sandbox());
385#endif // V8_ENABLE_SANDBOX
386}
387
388PtrComprCageAccessScope::~PtrComprCageAccessScope() {
389 V8HeapCompressionScheme::InitBase(cage_base_);
390#ifdef V8_EXTERNAL_CODE_SPACE
391 ExternalCodeCompressionScheme::InitBase(code_cage_base_);
392#endif // V8_EXTERNAL_CODE_SPACE
393 IsolateGroup::set_current(saved_current_isolate_group_);
394#ifdef V8_ENABLE_SANDBOX
395 Sandbox::set_current(saved_current_sandbox_);
396#endif // V8_ENABLE_SANDBOX
397}
398
399#endif // V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
400
401} // namespace internal
402} // namespace v8
403
404#endif // V8_COMMON_PTR_COMPR_INL_H_
static V8_INLINE void InitBase(Address base)
#define HAS_SMI_TAG(value)
Definition globals.h:1771
TNode< Object > callback
ZoneVector< RpoNumber > & result
uintptr_t Address
Definition memory.h:13
V8_INLINE constexpr PtrComprCageBase GetPtrComprCageBaseFromOnHeapAddress(Address address)
constexpr size_t kMinExpectedOSPageSize
Definition globals.h:510
Address Tagged_t
Definition globals.h:547
V8_INLINE PtrComprCageBase GetPtrComprCageBase()
#define UNREACHABLE()
Definition logging.h:67
#define DCHECK_WITH_MSG(condition, msg)
Definition logging.h:182
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
constexpr T RoundDown(T x, intptr_t m)
Definition macros.h:371
#define V8_INLINE
Definition v8config.h:500
#define V8_ASSUME
Definition v8config.h:533
#define V8_CONST
Definition v8config.h:555
#define V8_ASSUME_ALIGNED(ptr, alignment)
Definition v8config.h:545