forked from nodejs/node
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathptr-compr.h
More file actions
265 lines (227 loc) Β· 10.4 KB
/
Copy pathptr-compr.h
File metadata and controls
265 lines (227 loc) Β· 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMMON_PTR_COMPR_H_
#define V8_COMMON_PTR_COMPR_H_
#include "src/base/memory.h"
#include "src/common/globals.h"
namespace v8::internal {
class IsolateGroup;
#ifdef V8_ENABLE_SANDBOX
class Sandbox;
#endif // V8_ENABLE_SANDBOX
// This is just a collection of common compression scheme related functions.
// Each pointer compression cage then has its own compression scheme, which
// mainly differes in the cage base address they use.
template <typename Cage>
class V8HeapCompressionSchemeImpl {
public:
V8_INLINE static constexpr Address GetPtrComprCageBaseAddress(
Address on_heap_addr);
V8_INLINE static Address GetPtrComprCageBaseAddress(
PtrComprCageBase cage_base);
// Compresses full-pointer representation of a tagged value to on-heap
// representation.
// Must only be used for compressing object pointers since this function
// assumes that we deal with a valid address inside the pointer compression
// cage.
V8_INLINE static Tagged_t CompressObject(Address tagged);
// Compress a potentially invalid pointer.
V8_INLINE static constexpr Tagged_t CompressAny(Address tagged);
// Decompresses smi value.
V8_INLINE static Address DecompressTaggedSigned(Tagged_t raw_value);
// Decompresses any tagged value, preserving both weak- and smi- tags.
V8_INLINE static Address DecompressTagged(Tagged_t raw_value);
// Given a 64bit raw value, found on the stack, calls the callback function
// with all possible pointers that may be "contained" in compressed form in
// this value, either as complete compressed pointers or as intermediate
// (half-computed) results.
template <typename ProcessPointerCallback>
V8_INLINE static void ProcessIntermediatePointers(
Address raw_value, ProcessPointerCallback callback);
// Process-wide cage base value used for decompression.
V8_INLINE static void InitBase(Address base);
V8_CONST V8_INLINE static Address base();
};
// The main pointer compression cage, used for most objects.
class MainCage : public AllStatic {
friend class V8HeapCompressionSchemeImpl<MainCage>;
// These non-inlined accessors to base_ field are used in component builds
// where cross-component access to thread local variables is not allowed.
static V8_EXPORT_PRIVATE Address base_non_inlined();
static V8_EXPORT_PRIVATE void set_base_non_inlined(Address base);
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
static V8_EXPORT_PRIVATE uintptr_t base_ V8_CONSTINIT;
#else
static thread_local uintptr_t base_ V8_CONSTINIT;
#endif // V8_COMPRESS_POINTERS_IN_SHARED_CAGE
};
using V8HeapCompressionScheme = V8HeapCompressionSchemeImpl<MainCage>;
#ifdef V8_ENABLE_SANDBOX
// Compression scheme used for compressed pointers between trusted objects in
// the trusted heap space, outside of the sandbox.
class TrustedCage : public AllStatic {
friend class V8HeapCompressionSchemeImpl<TrustedCage>;
// Just to unify code with other cages in the multi-cage mode.
static V8_EXPORT_PRIVATE Address base_non_inlined();
static V8_EXPORT_PRIVATE void set_base_non_inlined(Address base);
static V8_EXPORT_PRIVATE uintptr_t base_ V8_CONSTINIT;
};
using TrustedSpaceCompressionScheme = V8HeapCompressionSchemeImpl<TrustedCage>;
#else
// The trusted cage does not exist in this case.
using TrustedSpaceCompressionScheme = V8HeapCompressionScheme;
#endif // V8_ENABLE_SANDBOX
// A compression scheme which can be passed if the only objects we ever expect
// to see are Smis (e.g. for {TaggedField<Smi, 0, SmiCompressionScheme>}).
class SmiCompressionScheme : public AllStatic {
public:
static Address DecompressTaggedSigned(Tagged_t raw_value) {
// For runtime code the upper 32-bits of the Smi value do not matter.
return static_cast<Address>(raw_value);
}
static Tagged_t CompressObject(Address tagged) {
DCHECK(HAS_SMI_TAG(tagged));
return static_cast<Tagged_t>(tagged);
}
};
#ifdef V8_EXTERNAL_CODE_SPACE
// Compression scheme used for fields containing InstructionStream objects
// (namely for the Code::code field).
// Unlike the V8HeapCompressionScheme this one allows the cage to cross 4GB
// boundary at a price of making decompression slightly more complex.
// The former outweighs the latter because it gives us more flexibility in
// allocating the code range closer to .text section in the process address
// space. At the same time decompression of the external code field happens
// relatively rarely during GC.
// The base can be any value such that [base, base + 4GB) contains the whole
// code range.
//
// This scheme works as follows:
// --|----------{---------|------}--------------|--
// 4GB | 4GB | 4GB
// +-- code range --+
// |
// cage base
//
// * Cage base value is OS page aligned for simplicity (although it's not
// strictly necessary).
// * Code range size is smaller than or equal to 4GB.
// * Compression is just a truncation to 32-bits value.
// * Decompression of a pointer:
// - if "compressed" cage base is <= than compressed value then one just
// needs to OR the upper 32-bits of the case base to get the decompressed
// value.
// - if compressed value is smaller than "compressed" cage base then ORing
// the upper 32-bits of the cage base is not enough because the resulting
// value will be off by 4GB, which has to be added to the result.
// - note that decompression doesn't modify the lower 32-bits of the value.
// * Decompression of Smi values is made a no-op for simplicity given that
// on the hot paths of decompressing the Code pointers it's already known
// that the value is not a Smi.
//
class ExternalCodeCompressionScheme {
public:
V8_INLINE static Address PrepareCageBaseAddress(Address on_heap_addr);
// Note that this compression scheme doesn't allow reconstruction of the cage
// base value from any arbitrary value, thus the cage base has to be passed
// explicitly to the decompression functions.
static Address GetPtrComprCageBaseAddress(Address on_heap_addr) = delete;
V8_INLINE static Address GetPtrComprCageBaseAddress(
PtrComprCageBase cage_base);
// Compresses full-pointer representation of a tagged value to on-heap
// representation.
// Must only be used for compressing object pointers (incl. SMI) since this
// function assumes pointers to be inside the pointer compression cage.
V8_INLINE static Tagged_t CompressObject(Address tagged);
// Compress anything that does not follow the above requirements (e.g. a maybe
// object, or a marker bit pattern).
V8_INLINE static constexpr Tagged_t CompressAny(Address tagged);
// Decompresses any tagged value, preserving both weak- and smi- tags.
V8_INLINE static Address DecompressTagged(Tagged_t raw_value);
// Process-wide cage base value used for decompression.
V8_INLINE static void InitBase(Address base);
V8_INLINE static Address base();
// Given a 64bit raw value, found on the stack, calls the callback function
// with all possible pointers that may be "contained" in compressed form in
// this value, either as complete compressed pointers or as intermediate
// (half-computed) results.
template <typename ProcessPointerCallback>
V8_INLINE static void ProcessIntermediatePointers(
Address raw_value, ProcessPointerCallback callback);
private:
// These non-inlined accessors to base_ field are used in component builds
// where cross-component access to thread local variables is not allowed.
static V8_EXPORT_PRIVATE Address base_non_inlined();
static V8_EXPORT_PRIVATE void set_base_non_inlined(Address base);
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
static V8_EXPORT_PRIVATE uintptr_t base_ V8_CONSTINIT;
#else
static thread_local uintptr_t base_ V8_CONSTINIT;
#endif // V8_COMPRESS_POINTERS_IN_SHARED_CAGE
};
#endif // V8_EXTERNAL_CODE_SPACE
// Accessors for fields that may be unaligned due to pointer compression.
template <typename V>
static inline V ReadMaybeUnalignedValue(Address p) {
// Pointer compression causes types larger than kTaggedSize to be unaligned.
#ifdef V8_COMPRESS_POINTERS
constexpr bool v8_pointer_compression_unaligned = sizeof(V) > kTaggedSize;
#else
constexpr bool v8_pointer_compression_unaligned = false;
#endif
// Bug(v8:8875) Double fields may be unaligned.
constexpr bool unaligned_double_field =
std::is_same<V, double>::value && kDoubleSize > kTaggedSize;
if (unaligned_double_field || v8_pointer_compression_unaligned) {
return base::ReadUnalignedValue<V>(p);
} else {
return base::Memory<V>(p);
}
}
template <typename V>
static inline void WriteMaybeUnalignedValue(Address p, V value) {
// Pointer compression causes types larger than kTaggedSize to be unaligned.
#ifdef V8_COMPRESS_POINTERS
constexpr bool v8_pointer_compression_unaligned = sizeof(V) > kTaggedSize;
#else
constexpr bool v8_pointer_compression_unaligned = false;
#endif
// Bug(v8:8875) Double fields may be unaligned.
constexpr bool unaligned_double_field =
std::is_same<V, double>::value && kDoubleSize > kTaggedSize;
if (unaligned_double_field || v8_pointer_compression_unaligned) {
base::WriteUnalignedValue<V>(p, value);
} else {
base::Memory<V>(p) = value;
}
}
// When multi-cage pointer compression mode is enabled this scope object
// saves current cage's base values and sets them according to given Isolate.
// For all other configurations this scope object is a no-op.
// Note: In most cases you want a full `SetCurrentIsolateScope` which also
// updates TLS to make the isolate the "current" isolate.
#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
class V8_NODISCARD PtrComprCageAccessScope final {
public:
V8_INLINE explicit PtrComprCageAccessScope(Isolate* isolate);
V8_INLINE ~PtrComprCageAccessScope();
private:
const Address cage_base_;
#ifdef V8_EXTERNAL_CODE_SPACE
const Address code_cage_base_;
#endif // V8_EXTERNAL_CODE_SPACE
IsolateGroup* saved_current_isolate_group_;
#ifdef V8_ENABLE_SANDBOX
Sandbox* saved_current_sandbox_;
#endif // V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
};
#else // V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
class V8_NODISCARD PtrComprCageAccessScope final {
public:
V8_INLINE explicit PtrComprCageAccessScope(Isolate* isolate) {}
};
#endif // V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
V8_INLINE PtrComprCageBase GetPtrComprCageBase();
} // namespace v8::internal
#endif // V8_COMMON_PTR_COMPR_H_