libv8-node 18.13.0.1-x86_64-linux → 19.9.0.0-x86_64-linux
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/libv8/node/version.rb +3 -3
- data/vendor/v8/include/cppgc/common.h +0 -1
- data/vendor/v8/include/cppgc/cross-thread-persistent.h +7 -8
- data/vendor/v8/include/cppgc/heap-consistency.h +46 -3
- data/vendor/v8/include/cppgc/heap-handle.h +43 -0
- data/vendor/v8/include/cppgc/heap-statistics.h +2 -2
- data/vendor/v8/include/cppgc/heap.h +3 -7
- data/vendor/v8/include/cppgc/internal/api-constants.h +11 -1
- data/vendor/v8/include/cppgc/internal/base-page-handle.h +45 -0
- data/vendor/v8/include/cppgc/internal/caged-heap-local-data.h +40 -8
- data/vendor/v8/include/cppgc/internal/caged-heap.h +61 -0
- data/vendor/v8/include/cppgc/internal/gc-info.h +0 -1
- data/vendor/v8/include/cppgc/internal/member-storage.h +236 -0
- data/vendor/v8/include/cppgc/internal/name-trait.h +21 -6
- data/vendor/v8/include/cppgc/internal/persistent-node.h +11 -13
- data/vendor/v8/include/cppgc/internal/pointer-policies.h +28 -7
- data/vendor/v8/include/cppgc/internal/write-barrier.h +143 -101
- data/vendor/v8/include/cppgc/liveness-broker.h +8 -7
- data/vendor/v8/include/cppgc/member.h +364 -89
- data/vendor/v8/include/cppgc/name-provider.h +4 -4
- data/vendor/v8/include/cppgc/persistent.h +5 -9
- data/vendor/v8/include/cppgc/platform.h +2 -2
- data/vendor/v8/include/cppgc/sentinel-pointer.h +1 -1
- data/vendor/v8/include/cppgc/trace-trait.h +4 -0
- data/vendor/v8/include/cppgc/type-traits.h +9 -0
- data/vendor/v8/include/cppgc/visitor.h +89 -57
- data/vendor/v8/include/v8-callbacks.h +19 -5
- data/vendor/v8/include/v8-context.h +13 -8
- data/vendor/v8/include/v8-cppgc.h +12 -0
- data/vendor/v8/include/v8-date.h +5 -0
- data/vendor/v8/include/v8-embedder-heap.h +8 -3
- data/vendor/v8/include/v8-exception.h +1 -1
- data/vendor/v8/include/v8-fast-api-calls.h +46 -32
- data/vendor/v8/include/v8-function.h +8 -0
- data/vendor/v8/include/v8-initialization.h +23 -49
- data/vendor/v8/include/v8-inspector.h +13 -7
- data/vendor/v8/include/v8-internal.h +328 -123
- data/vendor/v8/include/v8-isolate.h +27 -42
- data/vendor/v8/include/v8-local-handle.h +5 -5
- data/vendor/v8/include/v8-locker.h +0 -11
- data/vendor/v8/include/v8-maybe.h +24 -1
- data/vendor/v8/include/v8-message.h +2 -4
- data/vendor/v8/include/v8-metrics.h +20 -38
- data/vendor/v8/include/v8-microtask-queue.h +1 -1
- data/vendor/v8/include/v8-object.h +8 -15
- data/vendor/v8/include/v8-persistent-handle.h +0 -2
- data/vendor/v8/include/v8-platform.h +54 -25
- data/vendor/v8/include/v8-primitive.h +8 -8
- data/vendor/v8/include/v8-profiler.h +84 -22
- data/vendor/v8/include/v8-regexp.h +2 -1
- data/vendor/v8/include/v8-script.h +62 -6
- data/vendor/v8/include/v8-template.h +13 -76
- data/vendor/v8/include/v8-unwinder-state.h +4 -4
- data/vendor/v8/include/v8-util.h +2 -4
- data/vendor/v8/include/v8-value-serializer.h +46 -23
- data/vendor/v8/include/v8-version.h +3 -3
- data/vendor/v8/include/v8-wasm.h +5 -62
- data/vendor/v8/include/v8-weak-callback-info.h +0 -7
- data/vendor/v8/include/v8config.h +280 -13
- data/vendor/v8/x86_64-linux/libv8/obj/libv8_monolith.a +0 -0
- metadata +5 -1
@@ -8,6 +8,8 @@
|
|
8
8
|
#include <stddef.h>
|
9
9
|
#include <stdint.h>
|
10
10
|
#include <string.h>
|
11
|
+
|
12
|
+
#include <atomic>
|
11
13
|
#include <type_traits>
|
12
14
|
|
13
15
|
#include "v8-version.h" // NOLINT(build/include_directory)
|
@@ -50,6 +52,7 @@ const int kHeapObjectTag = 1;
|
|
50
52
|
const int kWeakHeapObjectTag = 3;
|
51
53
|
const int kHeapObjectTagSize = 2;
|
52
54
|
const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1;
|
55
|
+
const intptr_t kHeapObjectReferenceTagMask = 1 << (kHeapObjectTagSize - 1);
|
53
56
|
|
54
57
|
// Tag information for fowarding pointers stored in object headers.
|
55
58
|
// 0b00 at the lowest 2 bits in the header indicates that the map word is a
|
@@ -157,15 +160,7 @@ V8_INLINE static constexpr internal::Address IntToSmi(int value) {
|
|
157
160
|
* Sandbox related types, constants, and functions.
|
158
161
|
*/
|
159
162
|
constexpr bool SandboxIsEnabled() {
|
160
|
-
#ifdef
|
161
|
-
return true;
|
162
|
-
#else
|
163
|
-
return false;
|
164
|
-
#endif
|
165
|
-
}
|
166
|
-
|
167
|
-
constexpr bool SandboxedExternalPointersAreEnabled() {
|
168
|
-
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
|
163
|
+
#ifdef V8_ENABLE_SANDBOX
|
169
164
|
return true;
|
170
165
|
#else
|
171
166
|
return false;
|
@@ -176,19 +171,18 @@ constexpr bool SandboxedExternalPointersAreEnabled() {
|
|
176
171
|
// for example by storing them as offset rather than as raw pointers.
|
177
172
|
using SandboxedPointer_t = Address;
|
178
173
|
|
179
|
-
|
180
|
-
// external pointers are enabled, these are stored in an external pointer table
|
181
|
-
// and referenced from HeapObjects through indices.
|
182
|
-
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
|
183
|
-
using ExternalPointer_t = uint32_t;
|
184
|
-
#else
|
185
|
-
using ExternalPointer_t = Address;
|
186
|
-
#endif
|
187
|
-
|
188
|
-
#ifdef V8_SANDBOX_IS_AVAILABLE
|
174
|
+
#ifdef V8_ENABLE_SANDBOX
|
189
175
|
|
190
176
|
// Size of the sandbox, excluding the guard regions surrounding it.
|
177
|
+
#ifdef V8_TARGET_OS_ANDROID
|
178
|
+
// On Android, most 64-bit devices seem to be configured with only 39 bits of
|
179
|
+
// virtual address space for userspace. As such, limit the sandbox to 128GB (a
|
180
|
+
// quarter of the total available address space).
|
181
|
+
constexpr size_t kSandboxSizeLog2 = 37; // 128 GB
|
182
|
+
#else
|
183
|
+
// Everywhere else use a 1TB sandbox.
|
191
184
|
constexpr size_t kSandboxSizeLog2 = 40; // 1 TB
|
185
|
+
#endif // V8_TARGET_OS_ANDROID
|
192
186
|
constexpr size_t kSandboxSize = 1ULL << kSandboxSizeLog2;
|
193
187
|
|
194
188
|
// Required alignment of the sandbox. For simplicity, we require the
|
@@ -213,20 +207,6 @@ static_assert((kSandboxGuardRegionSize % kSandboxAlignment) == 0,
|
|
213
207
|
"The size of the guard regions around the sandbox must be a "
|
214
208
|
"multiple of its required alignment.");
|
215
209
|
|
216
|
-
// Minimum size of the sandbox, excluding the guard regions surrounding it. If
|
217
|
-
// the virtual memory reservation for the sandbox fails, its size is currently
|
218
|
-
// halved until either the reservation succeeds or the minimum size is reached.
|
219
|
-
// A minimum of 32GB allows the 4GB pointer compression region as well as the
|
220
|
-
// ArrayBuffer partition and two 10GB Wasm memory cages to fit into the
|
221
|
-
// sandbox. 32GB should also be the minimum possible size of the userspace
|
222
|
-
// address space as there are some machine configurations with only 36 virtual
|
223
|
-
// address bits.
|
224
|
-
constexpr size_t kSandboxMinimumSize = 32ULL * GB;
|
225
|
-
|
226
|
-
static_assert(kSandboxMinimumSize <= kSandboxSize,
|
227
|
-
"The minimal size of the sandbox must be smaller or equal to the "
|
228
|
-
"regular size.");
|
229
|
-
|
230
210
|
// On OSes where reserving virtual memory is too expensive to reserve the
|
231
211
|
// entire address space backing the sandbox, notably Windows pre 8.1, we create
|
232
212
|
// a partially reserved sandbox that doesn't actually reserve most of the
|
@@ -239,82 +219,269 @@ static_assert(kSandboxMinimumSize <= kSandboxSize,
|
|
239
219
|
// well as the ArrayBuffer partition.
|
240
220
|
constexpr size_t kSandboxMinimumReservationSize = 8ULL * GB;
|
241
221
|
|
242
|
-
static_assert(kSandboxMinimumSize > kPtrComprCageReservationSize,
|
243
|
-
"The sandbox must be larger than the pointer compression cage "
|
244
|
-
"contained within it.");
|
245
222
|
static_assert(kSandboxMinimumReservationSize > kPtrComprCageReservationSize,
|
246
223
|
"The minimum reservation size for a sandbox must be larger than "
|
247
224
|
"the pointer compression cage contained within it.");
|
248
225
|
|
249
|
-
//
|
250
|
-
//
|
251
|
-
//
|
252
|
-
//
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
226
|
+
// The maximum buffer size allowed inside the sandbox. This is mostly dependent
|
227
|
+
// on the size of the guard regions around the sandbox: an attacker must not be
|
228
|
+
// able to construct a buffer that appears larger than the guard regions and
|
229
|
+
// thereby "reach out of" the sandbox.
|
230
|
+
constexpr size_t kMaxSafeBufferSizeForSandbox = 32ULL * GB - 1;
|
231
|
+
static_assert(kMaxSafeBufferSizeForSandbox <= kSandboxGuardRegionSize,
|
232
|
+
"The maximum allowed buffer size must not be larger than the "
|
233
|
+
"sandbox's guard regions");
|
234
|
+
|
235
|
+
constexpr size_t kBoundedSizeShift = 29;
|
236
|
+
static_assert(1ULL << (64 - kBoundedSizeShift) ==
|
237
|
+
kMaxSafeBufferSizeForSandbox + 1,
|
238
|
+
"The maximum size of a BoundedSize must be synchronized with the "
|
239
|
+
"kMaxSafeBufferSizeForSandbox");
|
240
|
+
|
241
|
+
#endif // V8_ENABLE_SANDBOX
|
242
|
+
|
243
|
+
#ifdef V8_COMPRESS_POINTERS
|
258
244
|
|
259
245
|
// The size of the virtual memory reservation for an external pointer table.
|
260
246
|
// This determines the maximum number of entries in a table. Using a maximum
|
261
247
|
// size allows omitting bounds checks on table accesses if the indices are
|
262
248
|
// guaranteed (e.g. through shifting) to be below the maximum index. This
|
263
249
|
// value must be a power of two.
|
264
|
-
static const size_t kExternalPointerTableReservationSize =
|
250
|
+
static const size_t kExternalPointerTableReservationSize = 512 * MB;
|
265
251
|
|
266
252
|
// The maximum number of entries in an external pointer table.
|
267
|
-
static const size_t
|
253
|
+
static const size_t kMaxExternalPointers =
|
268
254
|
kExternalPointerTableReservationSize / kApiSystemPointerSize;
|
269
255
|
|
270
256
|
// The external pointer table indices stored in HeapObjects as external
|
271
257
|
// pointers are shifted to the left by this amount to guarantee that they are
|
272
258
|
// smaller than the maximum table size.
|
273
|
-
static const uint32_t kExternalPointerIndexShift =
|
274
|
-
static_assert((1 << (32 - kExternalPointerIndexShift)) ==
|
275
|
-
kMaxSandboxedExternalPointers,
|
259
|
+
static const uint32_t kExternalPointerIndexShift = 6;
|
260
|
+
static_assert((1 << (32 - kExternalPointerIndexShift)) == kMaxExternalPointers,
|
276
261
|
"kExternalPointerTableReservationSize and "
|
277
262
|
"kExternalPointerIndexShift don't match");
|
278
263
|
|
279
|
-
#
|
280
|
-
|
281
|
-
//
|
282
|
-
|
283
|
-
|
284
|
-
//
|
285
|
-
|
286
|
-
//
|
287
|
-
//
|
288
|
-
//
|
289
|
-
//
|
290
|
-
//
|
291
|
-
//
|
264
|
+
#else // !V8_COMPRESS_POINTERS
|
265
|
+
|
266
|
+
// Needed for the V8.SandboxedExternalPointersCount histogram.
|
267
|
+
static const size_t kMaxExternalPointers = 0;
|
268
|
+
|
269
|
+
#endif // V8_COMPRESS_POINTERS
|
270
|
+
|
271
|
+
// A ExternalPointerHandle represents a (opaque) reference to an external
|
272
|
+
// pointer that can be stored inside the sandbox. A ExternalPointerHandle has
|
273
|
+
// meaning only in combination with an (active) Isolate as it references an
|
274
|
+
// external pointer stored in the currently active Isolate's
|
275
|
+
// ExternalPointerTable. Internally, an ExternalPointerHandles is simply an
|
276
|
+
// index into an ExternalPointerTable that is shifted to the left to guarantee
|
277
|
+
// that it is smaller than the size of the table.
|
278
|
+
using ExternalPointerHandle = uint32_t;
|
279
|
+
|
280
|
+
// ExternalPointers point to objects located outside the sandbox. When
|
281
|
+
// sandboxed external pointers are enabled, these are stored on heap as
|
282
|
+
// ExternalPointerHandles, otherwise they are simply raw pointers.
|
283
|
+
#ifdef V8_ENABLE_SANDBOX
|
284
|
+
using ExternalPointer_t = ExternalPointerHandle;
|
285
|
+
#else
|
286
|
+
using ExternalPointer_t = Address;
|
287
|
+
#endif
|
288
|
+
|
289
|
+
// When the sandbox is enabled, external pointers are stored in an external
|
290
|
+
// pointer table and are referenced from HeapObjects through an index (a
|
291
|
+
// "handle"). When stored in the table, the pointers are tagged with per-type
|
292
|
+
// tags to prevent type confusion attacks between different external objects.
|
293
|
+
// Besides type information bits, these tags also contain the GC marking bit
|
294
|
+
// which indicates whether the pointer table entry is currently alive. When a
|
295
|
+
// pointer is written into the table, the tag is ORed into the top bits. When
|
296
|
+
// that pointer is later loaded from the table, it is ANDed with the inverse of
|
297
|
+
// the expected tag. If the expected and actual type differ, this will leave
|
298
|
+
// some of the top bits of the pointer set, rendering the pointer inaccessible.
|
299
|
+
// The AND operation also removes the GC marking bit from the pointer.
|
300
|
+
//
|
301
|
+
// The tags are constructed such that UNTAG(TAG(0, T1), T2) != 0 for any two
|
302
|
+
// (distinct) tags T1 and T2. In practice, this is achieved by generating tags
|
303
|
+
// that all have the same number of zeroes and ones but different bit patterns.
|
304
|
+
// With N type tag bits, this allows for (N choose N/2) possible type tags.
|
305
|
+
// Besides the type tag bits, the tags also have the GC marking bit set so that
|
306
|
+
// the marking bit is automatically set when a pointer is written into the
|
307
|
+
// external pointer table (in which case it is clearly alive) and is cleared
|
308
|
+
// when the pointer is loaded. The exception to this is the free entry tag,
|
309
|
+
// which doesn't have the mark bit set, as the entry is not alive. This
|
292
310
|
// construction allows performing the type check and removing GC marking bits
|
293
|
-
//
|
294
|
-
//
|
295
|
-
//
|
296
|
-
|
311
|
+
// from the pointer in one efficient operation (bitwise AND). The number of
|
312
|
+
// available bits is limited in the following way: on x64, bits [47, 64) are
|
313
|
+
// generally available for tagging (userspace has 47 address bits available).
|
314
|
+
// On Arm64, userspace typically has a 40 or 48 bit address space. However, due
|
315
|
+
// to top-byte ignore (TBI) and memory tagging (MTE), the top byte is unusable
|
316
|
+
// for type checks as type-check failures would go unnoticed or collide with
|
317
|
+
// MTE bits. Some bits of the top byte can, however, still be used for the GC
|
318
|
+
// marking bit. The bits available for the type tags are therefore limited to
|
319
|
+
// [48, 56), i.e. (8 choose 4) = 70 different types.
|
320
|
+
// The following options exist to increase the number of possible types:
|
321
|
+
// - Using multiple ExternalPointerTables since tags can safely be reused
|
322
|
+
// across different tables
|
323
|
+
// - Using "extended" type checks, where additional type information is stored
|
324
|
+
// either in an adjacent pointer table entry or at the pointed-to location
|
325
|
+
// - Using a different tagging scheme, for example based on XOR which would
|
326
|
+
// allow for 2**8 different tags but require a separate operation to remove
|
327
|
+
// the marking bit
|
328
|
+
//
|
329
|
+
// The external pointer sandboxing mechanism ensures that every access to an
|
330
|
+
// external pointer field will result in a valid pointer of the expected type
|
331
|
+
// even in the presence of an attacker able to corrupt memory inside the
|
332
|
+
// sandbox. However, if any data related to the external object is stored
|
333
|
+
// inside the sandbox it may still be corrupted and so must be validated before
|
334
|
+
// use or moved into the external object. Further, an attacker will always be
|
335
|
+
// able to substitute different external pointers of the same type for each
|
336
|
+
// other. Therefore, code using external pointers must be written in a
|
337
|
+
// "substitution-safe" way, i.e. it must always be possible to substitute
|
338
|
+
// external pointers of the same type without causing memory corruption outside
|
339
|
+
// of the sandbox. Generally this is achieved by referencing any group of
|
340
|
+
// related external objects through a single external pointer.
|
341
|
+
//
|
342
|
+
// Currently we use bit 62 for the marking bit which should always be unused as
|
343
|
+
// it's part of the non-canonical address range. When Arm's top-byte ignore
|
344
|
+
// (TBI) is enabled, this bit will be part of the ignored byte, and we assume
|
345
|
+
// that the Embedder is not using this byte (really only this one bit) for any
|
346
|
+
// other purpose. This bit also does not collide with the memory tagging
|
347
|
+
// extension (MTE) which would use bits [56, 60).
|
348
|
+
constexpr uint64_t kExternalPointerMarkBit = 1ULL << 62;
|
349
|
+
constexpr uint64_t kExternalPointerTagMask = 0x40ff000000000000;
|
297
350
|
constexpr uint64_t kExternalPointerTagShift = 48;
|
298
|
-
|
351
|
+
|
352
|
+
// All possible 8-bit type tags.
|
353
|
+
// These are sorted so that tags can be grouped together and it can efficiently
|
354
|
+
// be checked if a tag belongs to a given group. See for example the
|
355
|
+
// IsSharedExternalPointerType routine.
|
356
|
+
constexpr uint64_t kAllExternalPointerTypeTags[] = {
|
357
|
+
0b00001111, 0b00010111, 0b00011011, 0b00011101, 0b00011110, 0b00100111,
|
358
|
+
0b00101011, 0b00101101, 0b00101110, 0b00110011, 0b00110101, 0b00110110,
|
359
|
+
0b00111001, 0b00111010, 0b00111100, 0b01000111, 0b01001011, 0b01001101,
|
360
|
+
0b01001110, 0b01010011, 0b01010101, 0b01010110, 0b01011001, 0b01011010,
|
361
|
+
0b01011100, 0b01100011, 0b01100101, 0b01100110, 0b01101001, 0b01101010,
|
362
|
+
0b01101100, 0b01110001, 0b01110010, 0b01110100, 0b01111000, 0b10000111,
|
363
|
+
0b10001011, 0b10001101, 0b10001110, 0b10010011, 0b10010101, 0b10010110,
|
364
|
+
0b10011001, 0b10011010, 0b10011100, 0b10100011, 0b10100101, 0b10100110,
|
365
|
+
0b10101001, 0b10101010, 0b10101100, 0b10110001, 0b10110010, 0b10110100,
|
366
|
+
0b10111000, 0b11000011, 0b11000101, 0b11000110, 0b11001001, 0b11001010,
|
367
|
+
0b11001100, 0b11010001, 0b11010010, 0b11010100, 0b11011000, 0b11100001,
|
368
|
+
0b11100010, 0b11100100, 0b11101000, 0b11110000};
|
369
|
+
|
299
370
|
// clang-format off
|
371
|
+
// New entries should be added with state "sandboxed".
|
372
|
+
// When adding new tags, please ensure that the code using these tags is
|
373
|
+
// "substitution-safe", i.e. still operate safely if external pointers of the
|
374
|
+
// same type are swapped by an attacker. See comment above for more details.
|
375
|
+
#define TAG(i) (kAllExternalPointerTypeTags[i])
|
376
|
+
|
377
|
+
// Shared external pointers are owned by the shared Isolate and stored in the
|
378
|
+
// shared external pointer table associated with that Isolate, where they can
|
379
|
+
// be accessed from multiple threads at the same time. The objects referenced
|
380
|
+
// in this way must therefore always be thread-safe.
|
381
|
+
#define SHARED_EXTERNAL_POINTER_TAGS(V) \
|
382
|
+
V(kFirstSharedTag, sandboxed, TAG(0)) \
|
383
|
+
V(kWaiterQueueNodeTag, sandboxed, TAG(0)) \
|
384
|
+
V(kExternalStringResourceTag, sandboxed, TAG(1)) \
|
385
|
+
V(kExternalStringResourceDataTag, sandboxed, TAG(2)) \
|
386
|
+
V(kLastSharedTag, sandboxed, TAG(2))
|
387
|
+
|
388
|
+
// External pointers using these tags are kept in a per-Isolate external
|
389
|
+
// pointer table and can only be accessed when this Isolate is active.
|
390
|
+
#define PER_ISOLATE_EXTERNAL_POINTER_TAGS(V) \
|
391
|
+
V(kForeignForeignAddressTag, sandboxed, TAG(10)) \
|
392
|
+
V(kNativeContextMicrotaskQueueTag, sandboxed, TAG(11)) \
|
393
|
+
V(kEmbedderDataSlotPayloadTag, sandboxed, TAG(12)) \
|
394
|
+
V(kExternalObjectValueTag, sandboxed, TAG(13)) \
|
395
|
+
V(kCallHandlerInfoCallbackTag, sandboxed, TAG(14)) \
|
396
|
+
V(kAccessorInfoGetterTag, sandboxed, TAG(15)) \
|
397
|
+
V(kAccessorInfoSetterTag, sandboxed, TAG(16)) \
|
398
|
+
V(kWasmInternalFunctionCallTargetTag, sandboxed, TAG(17)) \
|
399
|
+
V(kWasmTypeInfoNativeTypeTag, sandboxed, TAG(18)) \
|
400
|
+
V(kWasmExportedFunctionDataSignatureTag, sandboxed, TAG(19)) \
|
401
|
+
V(kWasmContinuationJmpbufTag, sandboxed, TAG(20)) \
|
402
|
+
V(kArrayBufferExtensionTag, sandboxed, TAG(21))
|
403
|
+
|
404
|
+
// All external pointer tags.
|
405
|
+
#define ALL_EXTERNAL_POINTER_TAGS(V) \
|
406
|
+
SHARED_EXTERNAL_POINTER_TAGS(V) \
|
407
|
+
PER_ISOLATE_EXTERNAL_POINTER_TAGS(V)
|
408
|
+
|
409
|
+
// When the sandbox is enabled, external pointers marked as "sandboxed" above
|
410
|
+
// use the external pointer table (i.e. are sandboxed). This allows a gradual
|
411
|
+
// rollout of external pointer sandboxing. If the sandbox is off, no external
|
412
|
+
// pointers are sandboxed.
|
413
|
+
//
|
414
|
+
// Sandboxed external pointer tags are available when compressing pointers even
|
415
|
+
// when the sandbox is off. Some tags (e.g. kWaiterQueueNodeTag) are used
|
416
|
+
// manually with the external pointer table even when the sandbox is off to ease
|
417
|
+
// alignment requirements.
|
418
|
+
#define sandboxed(X) (X << kExternalPointerTagShift) | kExternalPointerMarkBit
|
419
|
+
#define unsandboxed(X) kUnsandboxedExternalPointerTag
|
420
|
+
#if defined(V8_COMPRESS_POINTERS)
|
421
|
+
#define EXTERNAL_POINTER_TAG_ENUM(Name, State, Bits) Name = State(Bits),
|
422
|
+
#else
|
423
|
+
#define EXTERNAL_POINTER_TAG_ENUM(Name, State, Bits) Name = unsandboxed(Bits),
|
424
|
+
#endif
|
425
|
+
|
426
|
+
#define MAKE_TAG(HasMarkBit, TypeTag) \
|
427
|
+
((static_cast<uint64_t>(TypeTag) << kExternalPointerTagShift) | \
|
428
|
+
(HasMarkBit ? kExternalPointerMarkBit : 0))
|
300
429
|
enum ExternalPointerTag : uint64_t {
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
430
|
+
// Empty tag value. Mostly used as placeholder.
|
431
|
+
kExternalPointerNullTag = MAKE_TAG(0, 0b00000000),
|
432
|
+
// Tag to use for unsandboxed external pointers, which are still stored as
|
433
|
+
// raw pointers on the heap.
|
434
|
+
kUnsandboxedExternalPointerTag = MAKE_TAG(0, 0b00000000),
|
435
|
+
// External pointer tag that will match any external pointer. Use with care!
|
436
|
+
kAnyExternalPointerTag = MAKE_TAG(1, 0b11111111),
|
437
|
+
// The free entry tag has all type bits set so every type check with a
|
438
|
+
// different type fails. It also doesn't have the mark bit set as free
|
439
|
+
// entries are (by definition) not alive.
|
440
|
+
kExternalPointerFreeEntryTag = MAKE_TAG(0, 0b11111111),
|
441
|
+
// Evacuation entries are used during external pointer table compaction.
|
442
|
+
kExternalPointerEvacuationEntryTag = MAKE_TAG(1, 0b11100111),
|
443
|
+
|
444
|
+
ALL_EXTERNAL_POINTER_TAGS(EXTERNAL_POINTER_TAG_ENUM)
|
310
445
|
};
|
311
|
-
|
446
|
+
|
312
447
|
#undef MAKE_TAG
|
448
|
+
#undef unsandboxed
|
449
|
+
#undef sandboxed
|
450
|
+
#undef TAG
|
451
|
+
#undef EXTERNAL_POINTER_TAG_ENUM
|
452
|
+
|
453
|
+
// clang-format on
|
454
|
+
|
455
|
+
// True if the external pointer is sandboxed and so must be referenced through
|
456
|
+
// an external pointer table.
|
457
|
+
V8_INLINE static constexpr bool IsSandboxedExternalPointerType(
|
458
|
+
ExternalPointerTag tag) {
|
459
|
+
return tag != kUnsandboxedExternalPointerTag;
|
460
|
+
}
|
461
|
+
|
462
|
+
// True if the external pointer must be accessed from the shared isolate's
|
463
|
+
// external pointer table.
|
464
|
+
V8_INLINE static constexpr bool IsSharedExternalPointerType(
|
465
|
+
ExternalPointerTag tag) {
|
466
|
+
return tag >= kFirstSharedTag && tag <= kLastSharedTag;
|
467
|
+
}
|
468
|
+
|
469
|
+
// Sanity checks.
|
470
|
+
#define CHECK_SHARED_EXTERNAL_POINTER_TAGS(Tag, ...) \
|
471
|
+
static_assert(!IsSandboxedExternalPointerType(Tag) || \
|
472
|
+
IsSharedExternalPointerType(Tag));
|
473
|
+
#define CHECK_NON_SHARED_EXTERNAL_POINTER_TAGS(Tag, ...) \
|
474
|
+
static_assert(!IsSandboxedExternalPointerType(Tag) || \
|
475
|
+
!IsSharedExternalPointerType(Tag));
|
476
|
+
|
477
|
+
SHARED_EXTERNAL_POINTER_TAGS(CHECK_SHARED_EXTERNAL_POINTER_TAGS)
|
478
|
+
PER_ISOLATE_EXTERNAL_POINTER_TAGS(CHECK_NON_SHARED_EXTERNAL_POINTER_TAGS)
|
313
479
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
480
|
+
#undef CHECK_NON_SHARED_EXTERNAL_POINTER_TAGS
|
481
|
+
#undef CHECK_SHARED_EXTERNAL_POINTER_TAGS
|
482
|
+
|
483
|
+
#undef SHARED_EXTERNAL_POINTER_TAGS
|
484
|
+
#undef EXTERNAL_POINTER_TAGS
|
318
485
|
|
319
486
|
// {obj} must be the raw tagged pointer representation of a HeapObject
|
320
487
|
// that's guaranteed to never be in ReadOnlySpace.
|
@@ -324,9 +491,6 @@ V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);
|
|
324
491
|
// mode based on the current context and the closure. This returns true if the
|
325
492
|
// language mode is strict.
|
326
493
|
V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate);
|
327
|
-
|
328
|
-
V8_EXPORT bool CanHaveInternalField(int instance_type);
|
329
|
-
|
330
494
|
/**
|
331
495
|
* This class exports constants and functionality from within v8 that
|
332
496
|
* is necessary to implement inline functions in the v8 api. Don't
|
@@ -354,8 +518,10 @@ class Internals {
|
|
354
518
|
static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize;
|
355
519
|
static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize;
|
356
520
|
static const int kEmbedderDataSlotSize = kApiSystemPointerSize;
|
357
|
-
#ifdef
|
358
|
-
static const int
|
521
|
+
#ifdef V8_ENABLE_SANDBOX
|
522
|
+
static const int kEmbedderDataSlotExternalPointerOffset = kApiTaggedSize;
|
523
|
+
#else
|
524
|
+
static const int kEmbedderDataSlotExternalPointerOffset = 0;
|
359
525
|
#endif
|
360
526
|
static const int kNativeContextEmbedderDataOffset = 6 * kApiTaggedSize;
|
361
527
|
static const int kStringRepresentationAndEncodingMask = 0x0f;
|
@@ -365,15 +531,21 @@ class Internals {
|
|
365
531
|
|
366
532
|
static const uint32_t kNumIsolateDataSlots = 4;
|
367
533
|
static const int kStackGuardSize = 7 * kApiSystemPointerSize;
|
368
|
-
static const int kBuiltinTier0EntryTableSize =
|
369
|
-
static const int kBuiltinTier0TableSize =
|
534
|
+
static const int kBuiltinTier0EntryTableSize = 7 * kApiSystemPointerSize;
|
535
|
+
static const int kBuiltinTier0TableSize = 7 * kApiSystemPointerSize;
|
536
|
+
|
537
|
+
// ExternalPointerTable layout guarantees.
|
538
|
+
static const int kExternalPointerTableBufferOffset = 0;
|
539
|
+
static const int kExternalPointerTableSize = 4 * kApiSystemPointerSize;
|
370
540
|
|
371
541
|
// IsolateData layout guarantees.
|
372
542
|
static const int kIsolateCageBaseOffset = 0;
|
373
543
|
static const int kIsolateStackGuardOffset =
|
374
544
|
kIsolateCageBaseOffset + kApiSystemPointerSize;
|
375
|
-
static const int
|
545
|
+
static const int kVariousBooleanFlagsOffset =
|
376
546
|
kIsolateStackGuardOffset + kStackGuardSize;
|
547
|
+
static const int kBuiltinTier0EntryTableOffset =
|
548
|
+
kVariousBooleanFlagsOffset + kApiSystemPointerSize;
|
377
549
|
static const int kBuiltinTier0TableOffset =
|
378
550
|
kBuiltinTier0EntryTableOffset + kBuiltinTier0EntryTableSize;
|
379
551
|
static const int kIsolateEmbedderDataOffset =
|
@@ -386,14 +558,17 @@ class Internals {
|
|
386
558
|
kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize;
|
387
559
|
static const int kIsolateLongTaskStatsCounterOffset =
|
388
560
|
kIsolateFastApiCallTargetOffset + kApiSystemPointerSize;
|
561
|
+
#ifdef V8_COMPRESS_POINTERS
|
562
|
+
static const int kIsolateExternalPointerTableOffset =
|
563
|
+
kIsolateLongTaskStatsCounterOffset + kApiSizetSize;
|
564
|
+
static const int kIsolateSharedExternalPointerTableAddressOffset =
|
565
|
+
kIsolateExternalPointerTableOffset + kExternalPointerTableSize;
|
566
|
+
static const int kIsolateRootsOffset =
|
567
|
+
kIsolateSharedExternalPointerTableAddressOffset + kApiSystemPointerSize;
|
568
|
+
#else
|
389
569
|
static const int kIsolateRootsOffset =
|
390
570
|
kIsolateLongTaskStatsCounterOffset + kApiSizetSize;
|
391
|
-
|
392
|
-
static const int kExternalPointerTableBufferOffset = 0;
|
393
|
-
static const int kExternalPointerTableCapacityOffset =
|
394
|
-
kExternalPointerTableBufferOffset + kApiSystemPointerSize;
|
395
|
-
static const int kExternalPointerTableFreelistHeadOffset =
|
396
|
-
kExternalPointerTableCapacityOffset + kApiInt32Size;
|
571
|
+
#endif
|
397
572
|
|
398
573
|
static const int kUndefinedValueRootIndex = 4;
|
399
574
|
static const int kTheHoleValueRootIndex = 5;
|
@@ -404,9 +579,8 @@ class Internals {
|
|
404
579
|
|
405
580
|
static const int kNodeClassIdOffset = 1 * kApiSystemPointerSize;
|
406
581
|
static const int kNodeFlagsOffset = 1 * kApiSystemPointerSize + 3;
|
407
|
-
static const int kNodeStateMask =
|
582
|
+
static const int kNodeStateMask = 0x3;
|
408
583
|
static const int kNodeStateIsWeakValue = 2;
|
409
|
-
static const int kNodeStateIsPendingValue = 3;
|
410
584
|
|
411
585
|
static const int kFirstNonstringType = 0x80;
|
412
586
|
static const int kOddballType = 0x83;
|
@@ -481,6 +655,18 @@ class Internals {
|
|
481
655
|
return representation == kExternalTwoByteRepresentationTag;
|
482
656
|
}
|
483
657
|
|
658
|
+
V8_INLINE static constexpr bool CanHaveInternalField(int instance_type) {
|
659
|
+
static_assert(kJSObjectType + 1 == kFirstJSApiObjectType);
|
660
|
+
static_assert(kJSObjectType < kLastJSApiObjectType);
|
661
|
+
static_assert(kFirstJSApiObjectType < kLastJSApiObjectType);
|
662
|
+
// Check for IsJSObject() || IsJSSpecialApiObject() || IsJSApiObject()
|
663
|
+
return instance_type == kJSSpecialApiObjectType ||
|
664
|
+
// inlined version of base::IsInRange
|
665
|
+
(static_cast<unsigned>(static_cast<unsigned>(instance_type) -
|
666
|
+
static_cast<unsigned>(kJSObjectType)) <=
|
667
|
+
static_cast<unsigned>(kLastJSApiObjectType - kJSObjectType));
|
668
|
+
}
|
669
|
+
|
484
670
|
V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) {
|
485
671
|
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
|
486
672
|
return *addr & static_cast<uint8_t>(1U << shift);
|
@@ -532,6 +718,25 @@ class Internals {
|
|
532
718
|
return reinterpret_cast<internal::Address*>(addr);
|
533
719
|
}
|
534
720
|
|
721
|
+
#ifdef V8_ENABLE_SANDBOX
|
722
|
+
V8_INLINE static internal::Address* GetExternalPointerTableBase(
|
723
|
+
v8::Isolate* isolate) {
|
724
|
+
internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
|
725
|
+
kIsolateExternalPointerTableOffset +
|
726
|
+
kExternalPointerTableBufferOffset;
|
727
|
+
return *reinterpret_cast<internal::Address**>(addr);
|
728
|
+
}
|
729
|
+
|
730
|
+
V8_INLINE static internal::Address* GetSharedExternalPointerTableBase(
|
731
|
+
v8::Isolate* isolate) {
|
732
|
+
internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
|
733
|
+
kIsolateSharedExternalPointerTableAddressOffset;
|
734
|
+
addr = *reinterpret_cast<internal::Address*>(addr);
|
735
|
+
addr += kExternalPointerTableBufferOffset;
|
736
|
+
return *reinterpret_cast<internal::Address**>(addr);
|
737
|
+
}
|
738
|
+
#endif
|
739
|
+
|
535
740
|
template <typename T>
|
536
741
|
V8_INLINE static T ReadRawField(internal::Address heap_object_ptr,
|
537
742
|
int offset) {
|
@@ -572,38 +777,38 @@ class Internals {
|
|
572
777
|
#endif
|
573
778
|
}
|
574
779
|
|
575
|
-
V8_INLINE static
|
576
|
-
|
577
|
-
|
578
|
-
|
780
|
+
V8_INLINE static v8::Isolate* GetIsolateForSandbox(internal::Address obj) {
|
781
|
+
#ifdef V8_ENABLE_SANDBOX
|
782
|
+
return reinterpret_cast<v8::Isolate*>(
|
783
|
+
internal::IsolateFromNeverReadOnlySpaceObject(obj));
|
579
784
|
#else
|
580
785
|
// Not used in non-sandbox mode.
|
581
786
|
return nullptr;
|
582
787
|
#endif
|
583
788
|
}
|
584
789
|
|
585
|
-
|
586
|
-
const Isolate* isolate, ExternalPointer_t encoded_pointer,
|
587
|
-
ExternalPointerTag tag) {
|
588
|
-
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
|
589
|
-
return internal::DecodeExternalPointerImpl(isolate, encoded_pointer, tag);
|
590
|
-
#else
|
591
|
-
return encoded_pointer;
|
592
|
-
#endif
|
593
|
-
}
|
594
|
-
|
790
|
+
template <ExternalPointerTag tag>
|
595
791
|
V8_INLINE static internal::Address ReadExternalPointerField(
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
792
|
+
v8::Isolate* isolate, internal::Address heap_object_ptr, int offset) {
|
793
|
+
#ifdef V8_ENABLE_SANDBOX
|
794
|
+
if (IsSandboxedExternalPointerType(tag)) {
|
795
|
+
// See src/sandbox/external-pointer-table-inl.h. Logic duplicated here so
|
796
|
+
// it can be inlined and doesn't require an additional call.
|
797
|
+
internal::Address* table =
|
798
|
+
IsSharedExternalPointerType(tag)
|
799
|
+
? GetSharedExternalPointerTableBase(isolate)
|
800
|
+
: GetExternalPointerTableBase(isolate);
|
801
|
+
internal::ExternalPointerHandle handle =
|
802
|
+
ReadRawField<ExternalPointerHandle>(heap_object_ptr, offset);
|
803
|
+
uint32_t index = handle >> kExternalPointerIndexShift;
|
804
|
+
std::atomic<internal::Address>* ptr =
|
805
|
+
reinterpret_cast<std::atomic<internal::Address>*>(&table[index]);
|
806
|
+
internal::Address entry =
|
807
|
+
std::atomic_load_explicit(ptr, std::memory_order_relaxed);
|
808
|
+
return entry & ~tag;
|
809
|
+
}
|
606
810
|
#endif
|
811
|
+
return ReadRawField<Address>(heap_object_ptr, offset);
|
607
812
|
}
|
608
813
|
|
609
814
|
#ifdef V8_COMPRESS_POINTERS
|
@@ -652,7 +857,7 @@ class BackingStoreBase {};
|
|
652
857
|
|
653
858
|
// The maximum value in enum GarbageCollectionReason, defined in heap.h.
|
654
859
|
// This is needed for histograms sampling garbage collection reasons.
|
655
|
-
constexpr int kGarbageCollectionReasonMaxValue =
|
860
|
+
constexpr int kGarbageCollectionReasonMaxValue = 27;
|
656
861
|
|
657
862
|
} // namespace internal
|
658
863
|
|