libv8-node 23.6.1.0-arm64-darwin → 24.1.0.0-arm64-darwin

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/lib/libv8/node/version.rb +3 -3
  3. data/vendor/v8/arm64-darwin/libv8/obj/libv8_monolith.a +0 -0
  4. data/vendor/v8/include/cppgc/allocation.h +1 -2
  5. data/vendor/v8/include/cppgc/default-platform.h +3 -2
  6. data/vendor/v8/include/cppgc/heap-consistency.h +1 -1
  7. data/vendor/v8/include/cppgc/internal/api-constants.h +0 -17
  8. data/vendor/v8/include/cppgc/internal/base-page-handle.h +2 -4
  9. data/vendor/v8/include/cppgc/internal/caged-heap-local-data.h +0 -4
  10. data/vendor/v8/include/cppgc/internal/caged-heap.h +0 -4
  11. data/vendor/v8/include/cppgc/internal/conditional-stack-allocated.h +41 -0
  12. data/vendor/v8/include/cppgc/internal/logging.h +3 -3
  13. data/vendor/v8/include/cppgc/internal/member-storage.h +63 -20
  14. data/vendor/v8/include/cppgc/internal/persistent-node.h +8 -3
  15. data/vendor/v8/include/cppgc/internal/pointer-policies.h +48 -11
  16. data/vendor/v8/include/cppgc/macros.h +21 -0
  17. data/vendor/v8/include/cppgc/member.h +70 -36
  18. data/vendor/v8/include/cppgc/name-provider.h +3 -0
  19. data/vendor/v8/include/cppgc/platform.h +11 -0
  20. data/vendor/v8/include/cppgc/type-traits.h +1 -0
  21. data/vendor/v8/include/cppgc/visitor.h +25 -1
  22. data/vendor/v8/include/libplatform/libplatform-export.h +2 -2
  23. data/vendor/v8/include/libplatform/v8-tracing.h +0 -1
  24. data/vendor/v8/include/v8-array-buffer.h +111 -34
  25. data/vendor/v8/include/v8-callbacks.h +84 -26
  26. data/vendor/v8/include/v8-context.h +7 -6
  27. data/vendor/v8/include/v8-cppgc.h +2 -1
  28. data/vendor/v8/include/v8-data.h +5 -0
  29. data/vendor/v8/include/v8-debug.h +11 -0
  30. data/vendor/v8/include/v8-embedder-heap.h +1 -32
  31. data/vendor/v8/include/v8-exception.h +2 -0
  32. data/vendor/v8/include/v8-external-memory-accounter.h +60 -0
  33. data/vendor/v8/include/v8-fast-api-calls.h +17 -175
  34. data/vendor/v8/include/v8-function-callback.h +4 -33
  35. data/vendor/v8/include/v8-function.h +7 -0
  36. data/vendor/v8/include/v8-handle-base.h +18 -0
  37. data/vendor/v8/include/v8-initialization.h +9 -1
  38. data/vendor/v8/include/v8-inspector.h +8 -4
  39. data/vendor/v8/include/v8-internal.h +477 -399
  40. data/vendor/v8/include/v8-isolate.h +218 -151
  41. data/vendor/v8/include/v8-local-handle.h +56 -28
  42. data/vendor/v8/include/v8-maybe.h +2 -1
  43. data/vendor/v8/include/v8-memory-span.h +149 -24
  44. data/vendor/v8/include/v8-message.h +9 -1
  45. data/vendor/v8/include/v8-metrics.h +10 -0
  46. data/vendor/v8/include/v8-object.h +7 -2
  47. data/vendor/v8/include/v8-persistent-handle.h +17 -17
  48. data/vendor/v8/include/v8-platform.h +48 -13
  49. data/vendor/v8/include/v8-primitive.h +131 -6
  50. data/vendor/v8/include/v8-profiler.h +13 -1
  51. data/vendor/v8/include/v8-proxy.h +0 -1
  52. data/vendor/v8/include/v8-regexp.h +0 -1
  53. data/vendor/v8/include/v8-sandbox.h +3 -3
  54. data/vendor/v8/include/v8-script.h +21 -3
  55. data/vendor/v8/include/v8-source-location.h +6 -1
  56. data/vendor/v8/include/v8-template.h +8 -2
  57. data/vendor/v8/include/v8-trace-categories.h +23 -0
  58. data/vendor/v8/include/v8-traced-handle.h +16 -17
  59. data/vendor/v8/include/v8-typed-array.h +6 -10
  60. data/vendor/v8/include/v8-unwinder-state.h +2 -3
  61. data/vendor/v8/include/v8-value-serializer-version.h +3 -3
  62. data/vendor/v8/include/v8-value.h +18 -0
  63. data/vendor/v8/include/v8-version.h +4 -4
  64. data/vendor/v8/include/v8-wasm.h +24 -0
  65. data/vendor/v8/include/v8-weak-callback-info.h +20 -12
  66. data/vendor/v8/include/v8.h +3 -3
  67. data/vendor/v8/include/v8config.h +34 -40
  68. metadata +6 -7
  69. data/vendor/v8/include/cppgc/ephemeron-pair.h +0 -30
@@ -18,6 +18,22 @@
18
18
 
19
19
  #include "v8config.h" // NOLINT(build/include_directory)
20
20
 
21
+ // TODO(pkasting): Use <compare>/spaceship unconditionally after dropping
22
+ // support for old libstdc++ versions.
23
+ #if __has_include(<version>)
24
+ #include <version>
25
+ #endif
26
+ #if defined(__cpp_lib_three_way_comparison) && \
27
+ __cpp_lib_three_way_comparison >= 201711L && \
28
+ defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L
29
+ #include <compare>
30
+ #include <concepts>
31
+
32
+ #define V8_HAVE_SPACESHIP_OPERATOR 1
33
+ #else
34
+ #define V8_HAVE_SPACESHIP_OPERATOR 0
35
+ #endif
36
+
21
37
  namespace v8 {
22
38
 
23
39
  class Array;
@@ -28,7 +44,10 @@ class Isolate;
28
44
  namespace internal {
29
45
 
30
46
  class Heap;
47
+ class LocalHeap;
31
48
  class Isolate;
49
+ class IsolateGroup;
50
+ class LocalIsolate;
32
51
 
33
52
  typedef uintptr_t Address;
34
53
  static constexpr Address kNullAddress = 0;
@@ -144,15 +163,15 @@ struct SmiTagging<8> {
144
163
  std::is_signed_v<T>>* = nullptr>
145
164
  V8_INLINE static constexpr bool IsValidSmi(T value) {
146
165
  // To be representable as a long smi, the value must be a 32-bit integer.
147
- return (value == static_cast<int32_t>(value));
166
+ return std::numeric_limits<int32_t>::min() <= value &&
167
+ value <= std::numeric_limits<int32_t>::max();
148
168
  }
149
169
 
150
170
  template <class T,
151
171
  typename std::enable_if_t<std::is_integral_v<T> &&
152
172
  std::is_unsigned_v<T>>* = nullptr>
153
173
  V8_INLINE static constexpr bool IsValidSmi(T value) {
154
- return (static_cast<uintptr_t>(value) ==
155
- static_cast<uintptr_t>(static_cast<int32_t>(value)));
174
+ return value <= std::numeric_limits<int32_t>::max();
156
175
  }
157
176
  };
158
177
 
@@ -218,10 +237,6 @@ using SandboxedPointer_t = Address;
218
237
  // virtual address space for userspace. As such, limit the sandbox to 128GB (a
219
238
  // quarter of the total available address space).
220
239
  constexpr size_t kSandboxSizeLog2 = 37; // 128 GB
221
- #elif defined(V8_TARGET_ARCH_LOONG64)
222
- // Some Linux distros on LoongArch64 configured with only 40 bits of virtual
223
- // address space for userspace. Limit the sandbox to 256GB here.
224
- constexpr size_t kSandboxSizeLog2 = 38; // 256 GB
225
240
  #else
226
241
  // Everywhere else use a 1TB sandbox.
227
242
  constexpr size_t kSandboxSizeLog2 = 40; // 1 TB
@@ -242,9 +257,12 @@ constexpr size_t kSandboxAlignment = kPtrComprCageBaseAlignment;
242
257
  constexpr uint64_t kSandboxedPointerShift = 64 - kSandboxSizeLog2;
243
258
 
244
259
  // Size of the guard regions surrounding the sandbox. This assumes a worst-case
245
- // scenario of a 32-bit unsigned index used to access an array of 64-bit
246
- // values.
247
- constexpr size_t kSandboxGuardRegionSize = 32ULL * GB;
260
+ // scenario of a 32-bit unsigned index used to access an array of 64-bit values
261
+ // with an additional 4GB (compressed pointer) offset. In particular, accesses
262
+ // to TypedArrays are effectively computed as
263
+ // `entry_pointer = array->base + array->offset + index * array->element_size`.
264
+ // See also https://crbug.com/40070746 for more details.
265
+ constexpr size_t kSandboxGuardRegionSize = 32ULL * GB + 4ULL * GB;
248
266
 
249
267
  static_assert((kSandboxGuardRegionSize % kSandboxAlignment) == 0,
250
268
  "The size of the guard regions around the sandbox must be a "
@@ -295,7 +313,8 @@ constexpr size_t kExternalPointerTableReservationSize = 256 * MB;
295
313
 
296
314
  // The external pointer table indices stored in HeapObjects as external
297
315
  // pointers are shifted to the left by this amount to guarantee that they are
298
- // smaller than the maximum table size.
316
+ // smaller than the maximum table size even after the C++ compiler multiplies
317
+ // them by 8 to be used as indexes into a table of 64 bit pointers.
299
318
  constexpr uint32_t kExternalPointerIndexShift = 7;
300
319
  #else
301
320
  constexpr size_t kExternalPointerTableReservationSize = 512 * MB;
@@ -318,6 +337,16 @@ constexpr size_t kMaxExternalPointers = 0;
318
337
 
319
338
  #endif // V8_COMPRESS_POINTERS
320
339
 
340
+ constexpr uint64_t kExternalPointerMarkBit = 1ULL << 48;
341
+ constexpr uint64_t kExternalPointerTagShift = 49;
342
+ constexpr uint64_t kExternalPointerTagMask = 0x00fe000000000000ULL;
343
+ constexpr uint64_t kExternalPointerShiftedTagMask =
344
+ kExternalPointerTagMask >> kExternalPointerTagShift;
345
+ static_assert(kExternalPointerShiftedTagMask << kExternalPointerTagShift ==
346
+ kExternalPointerTagMask);
347
+ constexpr uint64_t kExternalPointerTagAndMarkbitMask = 0x00ff000000000000ULL;
348
+ constexpr uint64_t kExternalPointerPayloadMask = 0xff00ffffffffffffULL;
349
+
321
350
  // A ExternalPointerHandle represents a (opaque) reference to an external
322
351
  // pointer that can be stored inside the sandbox. A ExternalPointerHandle has
323
352
  // meaning only in combination with an (active) Isolate as it references an
@@ -386,47 +415,76 @@ constexpr size_t kMaxCppHeapPointers = 0;
386
415
 
387
416
  #endif // V8_COMPRESS_POINTERS
388
417
 
389
- // See `ExternalPointerHandle` for the main documentation. The difference to
390
- // `ExternalPointerHandle` is that the handle always refers to a
391
- // (external pointer, size) tuple. The handles are used in combination with a
392
- // dedicated external buffer table (EBT).
393
- using ExternalBufferHandle = uint32_t;
418
+ // Generic tag range struct to represent ranges of type tags.
419
+ //
420
+ // When referencing external objects via pointer tables, type tags are
421
+ // frequently necessary to guarantee type safety for the external objects. When
422
+ // support for subtyping is necessary, range-based type checks are used in
423
+ // which all subtypes of a given supertype use contiguous tags. This struct can
424
+ // then be used to represent such a type range.
425
+ //
426
+ // In addition, there is an option for performance tweaks: if the size of the
427
+ // type range corresponding to a supertype is a power of two and starts at a
428
+ // power of two (e.g. [0x100, 0x13f]), then the compiler can often optimize
429
+ // the type check to use even fewer instructions (essentially replace a AND +
430
+ // SUB with a single AND).
431
+ //
432
+ template <typename Tag>
433
+ struct TagRange {
434
+ static_assert(std::is_enum_v<Tag> &&
435
+ std::is_same_v<std::underlying_type_t<Tag>, uint16_t>,
436
+ "Tag parameter must be an enum with base type uint16_t");
437
+
438
+ // Construct the inclusive tag range [first, last].
439
+ constexpr TagRange(Tag first, Tag last) : first(first), last(last) {}
440
+
441
+ // Construct a tag range consisting of a single tag.
442
+ //
443
+ // A single tag is always implicitly convertible to a tag range. This greatly
444
+ // increases readability as most of the time, the exact tag of a field is
445
+ // known and so no tag range needs to explicitly be created for it.
446
+ constexpr TagRange(Tag tag) // NOLINT(runtime/explicit)
447
+ : first(tag), last(tag) {}
448
+
449
+ // Construct an empty tag range.
450
+ constexpr TagRange() : TagRange(static_cast<Tag>(0)) {}
451
+
452
+ // A tag range is considered empty if it only contains the null tag.
453
+ constexpr bool IsEmpty() const { return first == 0 && last == 0; }
454
+
455
+ constexpr size_t Size() const {
456
+ if (IsEmpty()) {
457
+ return 0;
458
+ } else {
459
+ return last - first + 1;
460
+ }
461
+ }
394
462
 
395
- // ExternalBuffer point to buffer located outside the sandbox. When the V8
396
- // sandbox is enabled, these are stored on heap as ExternalBufferHandles,
397
- // otherwise they are simply raw pointers.
398
- #ifdef V8_ENABLE_SANDBOX
399
- using ExternalBuffer_t = ExternalBufferHandle;
400
- #else
401
- using ExternalBuffer_t = Address;
402
- #endif
463
+ constexpr bool Contains(Tag tag) const {
464
+ // Need to perform the math with uint32_t. Otherwise, the uint16_ts would
465
+ // be promoted to (signed) int, allowing the compiler to (wrongly) assume
466
+ // that an underflow cannot happen as that would be undefined behavior.
467
+ return static_cast<uint32_t>(tag) - first <=
468
+ static_cast<uint32_t>(last) - first;
469
+ }
403
470
 
404
- #ifdef V8_TARGET_OS_ANDROID
405
- // The size of the virtual memory reservation for the external buffer table.
406
- // As with the external pointer table, a maximum table size in combination with
407
- // shifted indices allows omitting bounds checks.
408
- constexpr size_t kExternalBufferTableReservationSize = 64 * MB;
471
+ constexpr bool Contains(TagRange tag_range) const {
472
+ return tag_range.first >= first && tag_range.last <= last;
473
+ }
409
474
 
410
- // The external buffer handles are stores shifted to the left by this amount
411
- // to guarantee that they are smaller than the maximum table size.
412
- constexpr uint32_t kExternalBufferHandleShift = 10;
413
- #else
414
- constexpr size_t kExternalBufferTableReservationSize = 128 * MB;
415
- constexpr uint32_t kExternalBufferHandleShift = 9;
416
- #endif // V8_TARGET_OS_ANDROID
475
+ constexpr bool operator==(const TagRange other) const {
476
+ return first == other.first && last == other.last;
477
+ }
417
478
 
418
- // A null handle always references an entry that contains nullptr.
419
- constexpr ExternalBufferHandle kNullExternalBufferHandle = 0;
420
-
421
- // The maximum number of entries in an external buffer table.
422
- constexpr int kExternalBufferTableEntrySize = 16;
423
- constexpr int kExternalBufferTableEntrySizeLog2 = 4;
424
- constexpr size_t kMaxExternalBufferPointers =
425
- kExternalBufferTableReservationSize / kExternalBufferTableEntrySize;
426
- static_assert((1 << (32 - kExternalBufferHandleShift)) ==
427
- kMaxExternalBufferPointers,
428
- "kExternalBufferTableReservationSize and "
429
- "kExternalBufferHandleShift don't match");
479
+ constexpr size_t hash_value() const {
480
+ static_assert(std::is_same_v<std::underlying_type_t<Tag>, uint16_t>);
481
+ return (static_cast<size_t>(first) << 16) | last;
482
+ }
483
+
484
+ // Internally we represent tag ranges as half-open ranges [first, last).
485
+ const Tag first;
486
+ const Tag last;
487
+ };
430
488
 
431
489
  //
432
490
  // External Pointers.
@@ -435,41 +493,12 @@ static_assert((1 << (32 - kExternalBufferHandleShift)) ==
435
493
  // pointer table and are referenced from HeapObjects through an index (a
436
494
  // "handle"). When stored in the table, the pointers are tagged with per-type
437
495
  // tags to prevent type confusion attacks between different external objects.
438
- // Besides type information bits, these tags also contain the GC marking bit
439
- // which indicates whether the pointer table entry is currently alive. When a
440
- // pointer is written into the table, the tag is ORed into the top bits. When
441
- // that pointer is later loaded from the table, it is ANDed with the inverse of
442
- // the expected tag. If the expected and actual type differ, this will leave
443
- // some of the top bits of the pointer set, rendering the pointer inaccessible.
444
- // The AND operation also removes the GC marking bit from the pointer.
445
496
  //
446
- // The tags are constructed such that UNTAG(TAG(0, T1), T2) != 0 for any two
447
- // (distinct) tags T1 and T2. In practice, this is achieved by generating tags
448
- // that all have the same number of zeroes and ones but different bit patterns.
449
- // With N type tag bits, this allows for (N choose N/2) possible type tags.
450
- // Besides the type tag bits, the tags also have the GC marking bit set so that
451
- // the marking bit is automatically set when a pointer is written into the
452
- // external pointer table (in which case it is clearly alive) and is cleared
453
- // when the pointer is loaded. The exception to this is the free entry tag,
454
- // which doesn't have the mark bit set, as the entry is not alive. This
455
- // construction allows performing the type check and removing GC marking bits
456
- // from the pointer in one efficient operation (bitwise AND). The number of
457
- // available bits is limited in the following way: on x64, bits [47, 64) are
458
- // generally available for tagging (userspace has 47 address bits available).
459
- // On Arm64, userspace typically has a 40 or 48 bit address space. However, due
460
- // to top-byte ignore (TBI) and memory tagging (MTE), the top byte is unusable
461
- // for type checks as type-check failures would go unnoticed or collide with
462
- // MTE bits. Some bits of the top byte can, however, still be used for the GC
463
- // marking bit. The bits available for the type tags are therefore limited to
464
- // [48, 56), i.e. (8 choose 4) = 70 different types.
465
- // The following options exist to increase the number of possible types:
466
- // - Using multiple ExternalPointerTables since tags can safely be reused
467
- // across different tables
468
- // - Using "extended" type checks, where additional type information is stored
469
- // either in an adjacent pointer table entry or at the pointed-to location
470
- // - Using a different tagging scheme, for example based on XOR which would
471
- // allow for 2**8 different tags but require a separate operation to remove
472
- // the marking bit
497
+ // When loading an external pointer, a range of allowed tags can be specified.
498
+ // This way, type hierarchies can be supported. The main requirement for that
499
+ // is that all (transitive) child classes of a given parent class have type ids
500
+ // in the same range, and that there are no unrelated types in that range. For
501
+ // more details about how to assign type tags to types, see the TagRange class.
473
502
  //
474
503
  // The external pointer sandboxing mechanism ensures that every access to an
475
504
  // external pointer field will result in a valid pointer of the expected type
@@ -498,167 +527,136 @@ static_assert((1 << (32 - kExternalBufferHandleShift)) ==
498
527
  // for this purpose, instead of using the ExternalPointer accessors one needs to
499
528
  // use ExternalPointerHandles directly and use them to access the pointers in an
500
529
  // ExternalPointerTable.
501
- constexpr uint64_t kExternalPointerMarkBit = 1ULL << 62;
502
- constexpr uint64_t kExternalPointerTagMask = 0x40ff000000000000;
503
- constexpr uint64_t kExternalPointerTagMaskWithoutMarkBit = 0xff000000000000;
504
- constexpr uint64_t kExternalPointerTagShift = 48;
505
-
506
- // All possible 8-bit type tags.
507
- // These are sorted so that tags can be grouped together and it can efficiently
508
- // be checked if a tag belongs to a given group. See for example the
509
- // IsSharedExternalPointerType routine.
510
- constexpr uint64_t kAllTagsForAndBasedTypeChecking[] = {
511
- 0b00001111, 0b00010111, 0b00011011, 0b00011101, 0b00011110, 0b00100111,
512
- 0b00101011, 0b00101101, 0b00101110, 0b00110011, 0b00110101, 0b00110110,
513
- 0b00111001, 0b00111010, 0b00111100, 0b01000111, 0b01001011, 0b01001101,
514
- 0b01001110, 0b01010011, 0b01010101, 0b01010110, 0b01011001, 0b01011010,
515
- 0b01011100, 0b01100011, 0b01100101, 0b01100110, 0b01101001, 0b01101010,
516
- 0b01101100, 0b01110001, 0b01110010, 0b01110100, 0b01111000, 0b10000111,
517
- 0b10001011, 0b10001101, 0b10001110, 0b10010011, 0b10010101, 0b10010110,
518
- 0b10011001, 0b10011010, 0b10011100, 0b10100011, 0b10100101, 0b10100110,
519
- 0b10101001, 0b10101010, 0b10101100, 0b10110001, 0b10110010, 0b10110100,
520
- 0b10111000, 0b11000011, 0b11000101, 0b11000110, 0b11001001, 0b11001010,
521
- 0b11001100, 0b11010001, 0b11010010, 0b11010100, 0b11011000, 0b11100001,
522
- 0b11100010, 0b11100100, 0b11101000, 0b11110000};
523
-
524
- #define TAG(i) \
525
- ((kAllTagsForAndBasedTypeChecking[i] << kExternalPointerTagShift) | \
526
- kExternalPointerMarkBit)
527
-
528
- // clang-format off
529
-
530
- // When adding new tags, please ensure that the code using these tags is
531
- // "substitution-safe", i.e. still operate safely if external pointers of the
532
- // same type are swapped by an attacker. See comment above for more details.
533
-
534
- // Shared external pointers are owned by the shared Isolate and stored in the
535
- // shared external pointer table associated with that Isolate, where they can
536
- // be accessed from multiple threads at the same time. The objects referenced
537
- // in this way must therefore always be thread-safe.
538
- #define SHARED_EXTERNAL_POINTER_TAGS(V) \
539
- V(kFirstSharedTag, TAG(0)) \
540
- V(kWaiterQueueNodeTag, TAG(0)) \
541
- V(kExternalStringResourceTag, TAG(1)) \
542
- V(kExternalStringResourceDataTag, TAG(2)) \
543
- V(kLastSharedTag, TAG(2))
544
- // Leave some space in the tag range here for future shared tags.
545
-
546
- // External pointers using these tags are kept in a per-Isolate external
547
- // pointer table and can only be accessed when this Isolate is active.
548
- #define PER_ISOLATE_EXTERNAL_POINTER_TAGS(V) \
549
- V(kNativeContextMicrotaskQueueTag, TAG(5)) \
550
- V(kEmbedderDataSlotPayloadTag, TAG(6)) \
551
- /* This tag essentially stands for a `void*` pointer in the V8 API, and */ \
552
- /* it is the Embedder's responsibility to ensure type safety (against */ \
553
- /* substitution) and lifetime validity of these objects. */ \
554
- V(kExternalObjectValueTag, TAG(7)) \
555
- V(kFunctionTemplateInfoCallbackTag, TAG(8)) \
556
- V(kAccessorInfoGetterTag, TAG(9)) \
557
- V(kAccessorInfoSetterTag, TAG(10)) \
558
- V(kWasmInternalFunctionCallTargetTag, TAG(11)) \
559
- V(kWasmTypeInfoNativeTypeTag, TAG(12)) \
560
- V(kWasmExportedFunctionDataSignatureTag, TAG(13)) \
561
- V(kWasmContinuationJmpbufTag, TAG(14)) \
562
- V(kWasmStackMemoryTag, TAG(15)) \
563
- V(kWasmIndirectFunctionTargetTag, TAG(16)) \
564
- /* Foreigns */ \
565
- V(kGenericForeignTag, TAG(20)) \
566
- V(kApiNamedPropertyQueryCallbackTag, TAG(21)) \
567
- V(kApiNamedPropertyGetterCallbackTag, TAG(22)) \
568
- V(kApiNamedPropertySetterCallbackTag, TAG(23)) \
569
- V(kApiNamedPropertyDescriptorCallbackTag, TAG(24)) \
570
- V(kApiNamedPropertyDefinerCallbackTag, TAG(25)) \
571
- V(kApiNamedPropertyDeleterCallbackTag, TAG(26)) \
572
- V(kApiIndexedPropertyQueryCallbackTag, TAG(27)) \
573
- V(kApiIndexedPropertyGetterCallbackTag, TAG(28)) \
574
- V(kApiIndexedPropertySetterCallbackTag, TAG(29)) \
575
- V(kApiIndexedPropertyDescriptorCallbackTag, TAG(30)) \
576
- V(kApiIndexedPropertyDefinerCallbackTag, TAG(31)) \
577
- V(kApiIndexedPropertyDeleterCallbackTag, TAG(32)) \
578
- V(kApiIndexedPropertyEnumeratorCallbackTag, TAG(33)) \
579
- V(kApiAccessCheckCallbackTag, TAG(34)) \
580
- V(kApiAbortScriptExecutionCallbackTag, TAG(35)) \
581
- V(kSyntheticModuleTag, TAG(36)) \
582
- V(kMicrotaskCallbackTag, TAG(37)) \
583
- V(kMicrotaskCallbackDataTag, TAG(38)) \
584
- V(kCFunctionTag, TAG(39)) \
585
- V(kCFunctionInfoTag, TAG(40)) \
586
- V(kMessageListenerTag, TAG(41)) \
587
- V(kWaiterQueueForeignTag, TAG(42)) \
588
- /* Managed */ \
589
- V(kFirstManagedResourceTag, TAG(50)) \
590
- V(kGenericManagedTag, TAG(50)) \
591
- V(kWasmWasmStreamingTag, TAG(51)) \
592
- V(kWasmFuncDataTag, TAG(52)) \
593
- V(kWasmManagedDataTag, TAG(53)) \
594
- V(kWasmNativeModuleTag, TAG(54)) \
595
- V(kIcuBreakIteratorTag, TAG(55)) \
596
- V(kIcuUnicodeStringTag, TAG(56)) \
597
- V(kIcuListFormatterTag, TAG(57)) \
598
- V(kIcuLocaleTag, TAG(58)) \
599
- V(kIcuSimpleDateFormatTag, TAG(59)) \
600
- V(kIcuDateIntervalFormatTag, TAG(60)) \
601
- V(kIcuRelativeDateTimeFormatterTag, TAG(61)) \
602
- V(kIcuLocalizedNumberFormatterTag, TAG(62)) \
603
- V(kIcuPluralRulesTag, TAG(63)) \
604
- V(kIcuCollatorTag, TAG(64)) \
605
- V(kDisplayNamesInternalTag, TAG(65)) \
606
- /* External resources whose lifetime is tied to */ \
607
- /* their entry in the external pointer table but */ \
608
- /* which are not referenced via a Managed */ \
609
- V(kArrayBufferExtensionTag, TAG(66)) \
610
- V(kLastManagedResourceTag, TAG(66)) \
611
-
612
- // All external pointer tags.
613
- #define ALL_EXTERNAL_POINTER_TAGS(V) \
614
- SHARED_EXTERNAL_POINTER_TAGS(V) \
615
- PER_ISOLATE_EXTERNAL_POINTER_TAGS(V)
616
-
617
- #define EXTERNAL_POINTER_TAG_ENUM(Name, Tag) Name = Tag,
618
- #define MAKE_TAG(HasMarkBit, TypeTag) \
619
- ((static_cast<uint64_t>(TypeTag) << kExternalPointerTagShift) | \
620
- (HasMarkBit ? kExternalPointerMarkBit : 0))
621
- enum ExternalPointerTag : uint64_t {
622
- // Empty tag value. Mostly used as placeholder.
623
- kExternalPointerNullTag = MAKE_TAG(1, 0b00000000),
624
- // External pointer tag that will match any external pointer. Use with care!
625
- kAnyExternalPointerTag = MAKE_TAG(1, 0b11111111),
626
- // External pointer tag that will match any external pointer in a Foreign.
627
- // Use with care! If desired, this could be made more fine-granular.
628
- kAnyForeignTag = kAnyExternalPointerTag,
629
- // The free entry tag has all type bits set so every type check with a
630
- // different type fails. It also doesn't have the mark bit set as free
631
- // entries are (by definition) not alive.
632
- kExternalPointerFreeEntryTag = MAKE_TAG(0, 0b11111111),
633
- // Evacuation entries are used during external pointer table compaction.
634
- kExternalPointerEvacuationEntryTag = MAKE_TAG(1, 0b11111110),
635
- // Tag for zapped/invalidated entries. Those are considered to no longer be
636
- // in use and so have the marking bit cleared.
637
- kExternalPointerZappedEntryTag = MAKE_TAG(0, 0b11111101),
638
-
639
- ALL_EXTERNAL_POINTER_TAGS(EXTERNAL_POINTER_TAG_ENUM)
530
+ //
531
+ // The tag is currently in practice limited to 15 bits since it needs to fit
532
+ // together with a marking bit into the unused parts of a pointer.
533
+ enum ExternalPointerTag : uint16_t {
534
+ kFirstExternalPointerTag = 0,
535
+ kExternalPointerNullTag = 0,
536
+
537
+ // When adding new tags, please ensure that the code using these tags is
538
+ // "substitution-safe", i.e. still operate safely if external pointers of the
539
+ // same type are swapped by an attacker. See comment above for more details.
540
+
541
+ // Shared external pointers are owned by the shared Isolate and stored in the
542
+ // shared external pointer table associated with that Isolate, where they can
543
+ // be accessed from multiple threads at the same time. The objects referenced
544
+ // in this way must therefore always be thread-safe.
545
+ kFirstSharedExternalPointerTag,
546
+ kWaiterQueueNodeTag = kFirstSharedExternalPointerTag,
547
+ kExternalStringResourceTag,
548
+ kExternalStringResourceDataTag,
549
+ kLastSharedExternalPointerTag = kExternalStringResourceDataTag,
550
+
551
+ // External pointers using these tags are kept in a per-Isolate external
552
+ // pointer table and can only be accessed when this Isolate is active.
553
+ kNativeContextMicrotaskQueueTag,
554
+ kEmbedderDataSlotPayloadTag,
555
+ // This tag essentially stands for a `void*` pointer in the V8 API, and it is
556
+ // the Embedder's responsibility to ensure type safety (against substitution)
557
+ // and lifetime validity of these objects.
558
+ kExternalObjectValueTag,
559
+ kFirstMaybeReadOnlyExternalPointerTag,
560
+ kFunctionTemplateInfoCallbackTag = kFirstMaybeReadOnlyExternalPointerTag,
561
+ kAccessorInfoGetterTag,
562
+ kAccessorInfoSetterTag,
563
+ kLastMaybeReadOnlyExternalPointerTag = kAccessorInfoSetterTag,
564
+ kWasmInternalFunctionCallTargetTag,
565
+ kWasmTypeInfoNativeTypeTag,
566
+ kWasmExportedFunctionDataSignatureTag,
567
+ kWasmStackMemoryTag,
568
+ kWasmIndirectFunctionTargetTag,
569
+
570
+ // Foreigns
571
+ kFirstForeignExternalPointerTag,
572
+ kGenericForeignTag = kFirstForeignExternalPointerTag,
573
+ kApiNamedPropertyQueryCallbackTag,
574
+ kApiNamedPropertyGetterCallbackTag,
575
+ kApiNamedPropertySetterCallbackTag,
576
+ kApiNamedPropertyDescriptorCallbackTag,
577
+ kApiNamedPropertyDefinerCallbackTag,
578
+ kApiNamedPropertyDeleterCallbackTag,
579
+ kApiIndexedPropertyQueryCallbackTag,
580
+ kApiIndexedPropertyGetterCallbackTag,
581
+ kApiIndexedPropertySetterCallbackTag,
582
+ kApiIndexedPropertyDescriptorCallbackTag,
583
+ kApiIndexedPropertyDefinerCallbackTag,
584
+ kApiIndexedPropertyDeleterCallbackTag,
585
+ kApiIndexedPropertyEnumeratorCallbackTag,
586
+ kApiAccessCheckCallbackTag,
587
+ kApiAbortScriptExecutionCallbackTag,
588
+ kSyntheticModuleTag,
589
+ kMicrotaskCallbackTag,
590
+ kMicrotaskCallbackDataTag,
591
+ kCFunctionTag,
592
+ kCFunctionInfoTag,
593
+ kMessageListenerTag,
594
+ kWaiterQueueForeignTag,
595
+
596
+ // Managed
597
+ kFirstManagedResourceTag,
598
+ kFirstManagedExternalPointerTag = kFirstManagedResourceTag,
599
+ kGenericManagedTag = kFirstManagedExternalPointerTag,
600
+ kWasmWasmStreamingTag,
601
+ kWasmFuncDataTag,
602
+ kWasmManagedDataTag,
603
+ kWasmNativeModuleTag,
604
+ kIcuBreakIteratorTag,
605
+ kIcuUnicodeStringTag,
606
+ kIcuListFormatterTag,
607
+ kIcuLocaleTag,
608
+ kIcuSimpleDateFormatTag,
609
+ kIcuDateIntervalFormatTag,
610
+ kIcuRelativeDateTimeFormatterTag,
611
+ kIcuLocalizedNumberFormatterTag,
612
+ kIcuPluralRulesTag,
613
+ kIcuCollatorTag,
614
+ kDisplayNamesInternalTag,
615
+ kD8WorkerTag,
616
+ kD8ModuleEmbedderDataTag,
617
+ kLastForeignExternalPointerTag = kD8ModuleEmbedderDataTag,
618
+ kLastManagedExternalPointerTag = kLastForeignExternalPointerTag,
619
+ // External resources whose lifetime is tied to their entry in the external
620
+ // pointer table but which are not referenced via a Managed
621
+ kArrayBufferExtensionTag,
622
+ kLastManagedResourceTag = kArrayBufferExtensionTag,
623
+
624
+ kExternalPointerZappedEntryTag = 0x7d,
625
+ kExternalPointerEvacuationEntryTag = 0x7e,
626
+ kExternalPointerFreeEntryTag = 0x7f,
627
+ // The tags are limited to 7 bits, so the last tag is 0x7f.
628
+ kLastExternalPointerTag = 0x7f,
640
629
  };
641
630
 
642
- #undef MAKE_TAG
643
- #undef TAG
644
- #undef EXTERNAL_POINTER_TAG_ENUM
645
-
646
- // clang-format on
631
+ using ExternalPointerTagRange = TagRange<ExternalPointerTag>;
632
+
633
+ constexpr ExternalPointerTagRange kAnyExternalPointerTagRange(
634
+ kFirstExternalPointerTag, kLastExternalPointerTag);
635
+ constexpr ExternalPointerTagRange kAnySharedExternalPointerTagRange(
636
+ kFirstSharedExternalPointerTag, kLastSharedExternalPointerTag);
637
+ constexpr ExternalPointerTagRange kAnyForeignExternalPointerTagRange(
638
+ kFirstForeignExternalPointerTag, kLastForeignExternalPointerTag);
639
+ constexpr ExternalPointerTagRange kAnyManagedExternalPointerTagRange(
640
+ kFirstManagedExternalPointerTag, kLastManagedExternalPointerTag);
641
+ constexpr ExternalPointerTagRange kAnyMaybeReadOnlyExternalPointerTagRange(
642
+ kFirstMaybeReadOnlyExternalPointerTag,
643
+ kLastMaybeReadOnlyExternalPointerTag);
644
+ constexpr ExternalPointerTagRange kAnyManagedResourceExternalPointerTag(
645
+ kFirstManagedResourceTag, kLastManagedResourceTag);
647
646
 
648
647
  // True if the external pointer must be accessed from the shared isolate's
649
648
  // external pointer table.
650
649
  V8_INLINE static constexpr bool IsSharedExternalPointerType(
651
- ExternalPointerTag tag) {
652
- return tag >= kFirstSharedTag && tag <= kLastSharedTag;
650
+ ExternalPointerTagRange tag_range) {
651
+ return kAnySharedExternalPointerTagRange.Contains(tag_range);
653
652
  }
654
653
 
655
654
  // True if the external pointer may live in a read-only object, in which case
656
655
  // the table entry will be in the shared read-only segment of the external
657
656
  // pointer table.
658
657
  V8_INLINE static constexpr bool IsMaybeReadOnlyExternalPointerType(
659
- ExternalPointerTag tag) {
660
- return tag == kAccessorInfoGetterTag || tag == kAccessorInfoSetterTag ||
661
- tag == kFunctionTemplateInfoCallbackTag;
658
+ ExternalPointerTagRange tag_range) {
659
+ return kAnyMaybeReadOnlyExternalPointerTagRange.Contains(tag_range);
662
660
  }
663
661
 
664
662
  // True if the external pointer references an external object whose lifetime is
@@ -666,26 +664,23 @@ V8_INLINE static constexpr bool IsMaybeReadOnlyExternalPointerType(
666
664
  // In this case, the entry in the ExternalPointerTable always points to an
667
665
  // object derived from ExternalPointerTable::ManagedResource.
668
666
  V8_INLINE static constexpr bool IsManagedExternalPointerType(
669
- ExternalPointerTag tag) {
670
- return tag >= kFirstManagedResourceTag && tag <= kLastManagedResourceTag;
667
+ ExternalPointerTagRange tag_range) {
668
+ return kAnyManagedResourceExternalPointerTag.Contains(tag_range);
671
669
  }
672
670
 
673
- // Sanity checks.
674
- #define CHECK_SHARED_EXTERNAL_POINTER_TAGS(Tag, ...) \
675
- static_assert(IsSharedExternalPointerType(Tag));
676
- #define CHECK_NON_SHARED_EXTERNAL_POINTER_TAGS(Tag, ...) \
677
- static_assert(!IsSharedExternalPointerType(Tag));
678
-
679
- SHARED_EXTERNAL_POINTER_TAGS(CHECK_SHARED_EXTERNAL_POINTER_TAGS)
680
- PER_ISOLATE_EXTERNAL_POINTER_TAGS(CHECK_NON_SHARED_EXTERNAL_POINTER_TAGS)
681
-
682
- #undef CHECK_NON_SHARED_EXTERNAL_POINTER_TAGS
683
- #undef CHECK_SHARED_EXTERNAL_POINTER_TAGS
684
-
685
- #undef SHARED_EXTERNAL_POINTER_TAGS
686
- #undef EXTERNAL_POINTER_TAGS
671
+ // When an external poiner field can contain the null external pointer handle,
672
+ // the type checking mechanism needs to also check for null.
673
+ // TODO(saelo): this is mostly a temporary workaround to introduce range-based
674
+ // type checks. In the future, we should either (a) change the type tagging
675
+ // scheme so that null always passes or (b) (more likely) introduce dedicated
676
+ // null entries for those tags that need them (similar to other well-known
677
+ // empty value constants such as the empty fixed array).
678
+ V8_INLINE static constexpr bool ExternalPointerCanBeEmpty(
679
+ ExternalPointerTagRange tag_range) {
680
+ return tag_range.Contains(kArrayBufferExtensionTag) ||
681
+ tag_range.Contains(kEmbedderDataSlotPayloadTag);
682
+ }
687
683
 
688
- //
689
684
  // Indirect Pointers.
690
685
  //
691
686
  // When the sandbox is enabled, indirect pointers are used to reference
@@ -729,7 +724,7 @@ using TrustedPointerHandle = IndirectPointerHandle;
729
724
  // shifted indices allows omitting bounds checks.
730
725
  constexpr size_t kTrustedPointerTableReservationSize = 64 * MB;
731
726
 
732
- // The trusted pointer handles are stores shifted to the left by this amount
727
+ // The trusted pointer handles are stored shifted to the left by this amount
733
728
  // to guarantee that they are smaller than the maximum table size.
734
729
  constexpr uint32_t kTrustedPointerHandleShift = 9;
735
730
 
@@ -805,29 +800,6 @@ constexpr bool kAllCodeObjectsLiveInTrustedSpace =
805
800
  kRuntimeGeneratedCodeObjectsLiveInTrustedSpace &&
806
801
  kBuiltinCodeObjectsLiveInTrustedSpace;
807
802
 
808
- //
809
- // JavaScript Dispatch Table
810
- //
811
- // A JSDispatchHandle represents a 32-bit index into a JSDispatchTable.
812
- using JSDispatchHandle = uint32_t;
813
-
814
- constexpr JSDispatchHandle kNullJSDispatchHandle = 0;
815
-
816
- // The size of the virtual memory reservation for the JSDispatchTable.
817
- // As with the other tables, a maximum table size in combination with shifted
818
- // indices allows omitting bounds checks.
819
- constexpr size_t kJSDispatchTableReservationSize = 128 * MB;
820
- constexpr uint32_t kJSDispatchHandleShift = 9;
821
-
822
- // The maximum number of entries in a JSDispatchTable.
823
- constexpr int kJSDispatchTableEntrySize = 16;
824
- constexpr int kJSDispatchTableEntrySizeLog2 = 4;
825
- constexpr size_t kMaxJSDispatchEntries =
826
- kJSDispatchTableReservationSize / kJSDispatchTableEntrySize;
827
- static_assert((1 << (32 - kJSDispatchHandleShift)) == kMaxJSDispatchEntries,
828
- "kJSDispatchTableReservationSize and kJSDispatchEntryHandleShift "
829
- "don't match");
830
-
831
803
  // {obj} must be the raw tagged pointer representation of a HeapObject
832
804
  // that's guaranteed to never be in ReadOnlySpace.
833
805
  V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);
@@ -885,6 +857,7 @@ class Internals {
885
857
  static const int kNumberOfBooleanFlags = 6;
886
858
  static const int kErrorMessageParamSize = 1;
887
859
  static const int kTablesAlignmentPaddingSize = 1;
860
+ static const int kRegExpStaticResultOffsetsVectorSize = kApiSystemPointerSize;
888
861
  static const int kBuiltinTier0EntryTableSize = 7 * kApiSystemPointerSize;
889
862
  static const int kBuiltinTier0TableSize = 7 * kApiSystemPointerSize;
890
863
  static const int kLinearAllocationAreaSize = 3 * kApiSystemPointerSize;
@@ -895,7 +868,6 @@ class Internals {
895
868
  // ExternalPointerTable and TrustedPointerTable layout guarantees.
896
869
  static const int kExternalPointerTableBasePointerOffset = 0;
897
870
  static const int kExternalPointerTableSize = 2 * kApiSystemPointerSize;
898
- static const int kExternalBufferTableSize = 2 * kApiSystemPointerSize;
899
871
  static const int kTrustedPointerTableSize = 2 * kApiSystemPointerSize;
900
872
  static const int kTrustedPointerTableBasePointerOffset = 0;
901
873
 
@@ -907,9 +879,9 @@ class Internals {
907
879
  kIsolateStackGuardOffset + kStackGuardSize;
908
880
  static const int kErrorMessageParamOffset =
909
881
  kVariousBooleanFlagsOffset + kNumberOfBooleanFlags;
910
- static const int kBuiltinTier0EntryTableOffset = kErrorMessageParamOffset +
911
- kErrorMessageParamSize +
912
- kTablesAlignmentPaddingSize;
882
+ static const int kBuiltinTier0EntryTableOffset =
883
+ kErrorMessageParamOffset + kErrorMessageParamSize +
884
+ kTablesAlignmentPaddingSize + kRegExpStaticResultOffsetsVectorSize;
913
885
  static const int kBuiltinTier0TableOffset =
914
886
  kBuiltinTier0EntryTableOffset + kBuiltinTier0EntryTableSize;
915
887
  static const int kNewAllocationInfoOffset =
@@ -918,14 +890,15 @@ class Internals {
918
890
  kNewAllocationInfoOffset + kLinearAllocationAreaSize;
919
891
 
920
892
  static const int kFastCCallAlignmentPaddingSize =
921
- kApiSystemPointerSize == 8 ? 0 : kApiSystemPointerSize;
922
- static const int kIsolateFastCCallCallerFpOffset =
893
+ kApiSystemPointerSize == 8 ? 5 * kApiSystemPointerSize
894
+ : 1 * kApiSystemPointerSize;
895
+ static const int kIsolateFastCCallCallerPcOffset =
923
896
  kOldAllocationInfoOffset + kLinearAllocationAreaSize +
924
897
  kFastCCallAlignmentPaddingSize;
925
- static const int kIsolateFastCCallCallerPcOffset =
926
- kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize;
927
- static const int kIsolateFastApiCallTargetOffset =
898
+ static const int kIsolateFastCCallCallerFpOffset =
928
899
  kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize;
900
+ static const int kIsolateFastApiCallTargetOffset =
901
+ kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize;
929
902
  static const int kIsolateLongTaskStatsCounterOffset =
930
903
  kIsolateFastApiCallTargetOffset + kApiSystemPointerSize;
931
904
  static const int kIsolateThreadLocalTopOffset =
@@ -946,8 +919,14 @@ class Internals {
946
919
  kIsolateCppHeapPointerTableOffset + kExternalPointerTableSize;
947
920
  static const int kIsolateTrustedPointerTableOffset =
948
921
  kIsolateTrustedCageBaseOffset + kApiSystemPointerSize;
949
- static const int kIsolateApiCallbackThunkArgumentOffset =
922
+ static const int kIsolateSharedTrustedPointerTableAddressOffset =
950
923
  kIsolateTrustedPointerTableOffset + kTrustedPointerTableSize;
924
+ static const int kIsolateTrustedPointerPublishingScopeOffset =
925
+ kIsolateSharedTrustedPointerTableAddressOffset + kApiSystemPointerSize;
926
+ static const int kIsolateCodePointerTableBaseAddressOffset =
927
+ kIsolateTrustedPointerPublishingScopeOffset + kApiSystemPointerSize;
928
+ static const int kIsolateApiCallbackThunkArgumentOffset =
929
+ kIsolateCodePointerTableBaseAddressOffset + kApiSystemPointerSize;
951
930
  #else
952
931
  static const int kIsolateApiCallbackThunkArgumentOffset =
953
932
  kIsolateCppHeapPointerTableOffset + kExternalPointerTableSize;
@@ -956,8 +935,10 @@ class Internals {
956
935
  static const int kIsolateApiCallbackThunkArgumentOffset =
957
936
  kIsolateEmbedderDataOffset + kNumIsolateDataSlots * kApiSystemPointerSize;
958
937
  #endif // V8_COMPRESS_POINTERS
959
- static const int kContinuationPreservedEmbedderDataOffset =
938
+ static const int kIsolateRegexpExecVectorArgumentOffset =
960
939
  kIsolateApiCallbackThunkArgumentOffset + kApiSystemPointerSize;
940
+ static const int kContinuationPreservedEmbedderDataOffset =
941
+ kIsolateRegexpExecVectorArgumentOffset + kApiSystemPointerSize;
961
942
  static const int kIsolateRootsOffset =
962
943
  kContinuationPreservedEmbedderDataOffset + kApiSystemPointerSize;
963
944
 
@@ -969,12 +950,12 @@ class Internals {
969
950
 
970
951
  // These constants are copied from static-roots.h and guarded by static asserts.
971
952
  #define EXPORTED_STATIC_ROOTS_PTR_LIST(V) \
972
- V(UndefinedValue, 0x69) \
973
- V(NullValue, 0x85) \
974
- V(TrueValue, 0xc9) \
975
- V(FalseValue, 0xad) \
976
- V(EmptyString, 0xa1) \
977
- V(TheHoleValue, 0x791)
953
+ V(UndefinedValue, 0x11) \
954
+ V(NullValue, 0x2d) \
955
+ V(TrueValue, 0x71) \
956
+ V(FalseValue, 0x55) \
957
+ V(EmptyString, 0x49) \
958
+ V(TheHoleValue, 0x761)
978
959
 
979
960
  using Tagged_t = uint32_t;
980
961
  struct StaticReadOnlyRoot {
@@ -984,7 +965,7 @@ class Internals {
984
965
 
985
966
  // Use 0 for kStringMapLowerBound since string maps are the first maps.
986
967
  static constexpr Tagged_t kStringMapLowerBound = 0;
987
- static constexpr Tagged_t kStringMapUpperBound = 0x47d;
968
+ static constexpr Tagged_t kStringMapUpperBound = 0x425;
988
969
 
989
970
  #define PLUSONE(...) +1
990
971
  static constexpr size_t kNumberOfExportedStaticRoots =
@@ -1030,7 +1011,7 @@ class Internals {
1030
1011
 
1031
1012
  // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an
1032
1013
  // incremental GC once the external memory reaches this limit.
1033
- static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024;
1014
+ static constexpr size_t kExternalAllocationSoftLimit = 64 * 1024 * 1024;
1034
1015
 
1035
1016
  #ifdef V8_MAP_PACKING
1036
1017
  static const uintptr_t kMapWordMetadataMask = 0xffffULL << 48;
@@ -1272,15 +1253,15 @@ class Internals {
1272
1253
  #endif
1273
1254
  }
1274
1255
 
1275
- template <ExternalPointerTag tag>
1256
+ template <ExternalPointerTagRange tag_range>
1276
1257
  V8_INLINE static Address ReadExternalPointerField(v8::Isolate* isolate,
1277
1258
  Address heap_object_ptr,
1278
1259
  int offset) {
1279
1260
  #ifdef V8_ENABLE_SANDBOX
1280
- static_assert(tag != kExternalPointerNullTag);
1281
- // See src/sandbox/external-pointer-table-inl.h. Logic duplicated here so
1261
+ static_assert(!tag_range.IsEmpty());
1262
+ // See src/sandbox/external-pointer-table.h. Logic duplicated here so
1282
1263
  // it can be inlined and doesn't require an additional call.
1283
- Address* table = IsSharedExternalPointerType(tag)
1264
+ Address* table = IsSharedExternalPointerType(tag_range)
1284
1265
  ? GetSharedExternalPointerTableBase(isolate)
1285
1266
  : GetExternalPointerTableBase(isolate);
1286
1267
  internal::ExternalPointerHandle handle =
@@ -1289,7 +1270,14 @@ class Internals {
1289
1270
  std::atomic<Address>* ptr =
1290
1271
  reinterpret_cast<std::atomic<Address>*>(&table[index]);
1291
1272
  Address entry = std::atomic_load_explicit(ptr, std::memory_order_relaxed);
1292
- return entry & ~tag;
1273
+ ExternalPointerTag actual_tag = static_cast<ExternalPointerTag>(
1274
+ (entry & kExternalPointerTagMask) >> kExternalPointerTagShift);
1275
+ if (V8_LIKELY(tag_range.Contains(actual_tag))) {
1276
+ return entry & kExternalPointerPayloadMask;
1277
+ } else {
1278
+ return 0;
1279
+ }
1280
+ return entry;
1293
1281
  #else
1294
1282
  return ReadRawField<Address>(heap_object_ptr, offset);
1295
1283
  #endif // V8_ENABLE_SANDBOX
@@ -1343,7 +1331,7 @@ class BackingStoreBase {};
1343
1331
 
1344
1332
  // The maximum value in enum GarbageCollectionReason, defined in heap.h.
1345
1333
  // This is needed for histograms sampling garbage collection reasons.
1346
- constexpr int kGarbageCollectionReasonMaxValue = 27;
1334
+ constexpr int kGarbageCollectionReasonMaxValue = 29;
1347
1335
 
1348
1336
  // Base class for the address block allocator compatible with standard
1349
1337
  // containers, which registers its allocated range as strong roots.
@@ -1351,16 +1339,19 @@ class V8_EXPORT StrongRootAllocatorBase {
1351
1339
  public:
1352
1340
  Heap* heap() const { return heap_; }
1353
1341
 
1354
- bool operator==(const StrongRootAllocatorBase& other) const {
1355
- return heap_ == other.heap_;
1356
- }
1357
- bool operator!=(const StrongRootAllocatorBase& other) const {
1358
- return heap_ != other.heap_;
1342
+ friend bool operator==(const StrongRootAllocatorBase& a,
1343
+ const StrongRootAllocatorBase& b) {
1344
+ // TODO(pkasting): Replace this body with `= default` after dropping support
1345
+ // for old gcc versions.
1346
+ return a.heap_ == b.heap_;
1359
1347
  }
1360
1348
 
1361
1349
  protected:
1362
1350
  explicit StrongRootAllocatorBase(Heap* heap) : heap_(heap) {}
1351
+ explicit StrongRootAllocatorBase(LocalHeap* heap);
1363
1352
  explicit StrongRootAllocatorBase(Isolate* isolate);
1353
+ explicit StrongRootAllocatorBase(v8::Isolate* isolate);
1354
+ explicit StrongRootAllocatorBase(LocalIsolate* isolate);
1364
1355
 
1365
1356
  // Allocate/deallocate a range of n elements of type internal::Address.
1366
1357
  Address* allocate_impl(size_t n);
@@ -1380,9 +1371,8 @@ class StrongRootAllocator : private std::allocator<T> {
1380
1371
  public:
1381
1372
  using value_type = T;
1382
1373
 
1383
- explicit StrongRootAllocator(Heap* heap) {}
1384
- explicit StrongRootAllocator(Isolate* isolate) {}
1385
- explicit StrongRootAllocator(v8::Isolate* isolate) {}
1374
+ template <typename HeapOrIsolateT>
1375
+ explicit StrongRootAllocator(HeapOrIsolateT*) {}
1386
1376
  template <typename U>
1387
1377
  StrongRootAllocator(const StrongRootAllocator<U>& other) noexcept {}
1388
1378
 
@@ -1390,22 +1380,61 @@ class StrongRootAllocator : private std::allocator<T> {
1390
1380
  using std::allocator<T>::deallocate;
1391
1381
  };
1392
1382
 
1383
+ // TODO(pkasting): Replace with `requires` clauses after dropping support for
1384
+ // old gcc versions.
1385
+ template <typename Iterator, typename = void>
1386
+ inline constexpr bool kHaveIteratorConcept = false;
1387
+ template <typename Iterator>
1388
+ inline constexpr bool kHaveIteratorConcept<
1389
+ Iterator, std::void_t<typename Iterator::iterator_concept>> = true;
1390
+
1391
+ template <typename Iterator, typename = void>
1392
+ inline constexpr bool kHaveIteratorCategory = false;
1393
+ template <typename Iterator>
1394
+ inline constexpr bool kHaveIteratorCategory<
1395
+ Iterator, std::void_t<typename Iterator::iterator_category>> = true;
1396
+
1397
+ // Helper struct that contains an `iterator_concept` type alias only when either
1398
+ // `Iterator` or `std::iterator_traits<Iterator>` do.
1399
+ // Default: no alias.
1400
+ template <typename Iterator, typename = void>
1401
+ struct MaybeDefineIteratorConcept {};
1402
+ // Use `Iterator::iterator_concept` if available.
1403
+ template <typename Iterator>
1404
+ struct MaybeDefineIteratorConcept<
1405
+ Iterator, std::enable_if_t<kHaveIteratorConcept<Iterator>>> {
1406
+ using iterator_concept = typename Iterator::iterator_concept;
1407
+ };
1408
+ // Otherwise fall back to `std::iterator_traits<Iterator>` if possible.
1409
+ template <typename Iterator>
1410
+ struct MaybeDefineIteratorConcept<
1411
+ Iterator, std::enable_if_t<kHaveIteratorCategory<Iterator> &&
1412
+ !kHaveIteratorConcept<Iterator>>> {
1413
+ // There seems to be no feature-test macro covering this, so use the
1414
+ // presence of `<ranges>` as a crude proxy, since it was added to the
1415
+ // standard as part of the Ranges papers.
1416
+ // TODO(pkasting): Add this unconditionally after dropping support for old
1417
+ // libstdc++ versions.
1418
+ #if __has_include(<ranges>)
1419
+ using iterator_concept =
1420
+ typename std::iterator_traits<Iterator>::iterator_concept;
1421
+ #endif
1422
+ };
1423
+
1393
1424
  // A class of iterators that wrap some different iterator type.
1394
1425
  // If specified, ElementType is the type of element accessed by the wrapper
1395
1426
  // iterator; in this case, the actual reference and pointer types of Iterator
1396
1427
  // must be convertible to ElementType& and ElementType*, respectively.
1397
1428
  template <typename Iterator, typename ElementType = void>
1398
- class WrappedIterator {
1429
+ class WrappedIterator : public MaybeDefineIteratorConcept<Iterator> {
1399
1430
  public:
1400
1431
  static_assert(
1401
- !std::is_void_v<ElementType> ||
1432
+ std::is_void_v<ElementType> ||
1402
1433
  (std::is_convertible_v<typename std::iterator_traits<Iterator>::pointer,
1403
- ElementType*> &&
1434
+ std::add_pointer_t<ElementType>> &&
1404
1435
  std::is_convertible_v<typename std::iterator_traits<Iterator>::reference,
1405
- ElementType&>));
1436
+ std::add_lvalue_reference_t<ElementType>>));
1406
1437
 
1407
- using iterator_category =
1408
- typename std::iterator_traits<Iterator>::iterator_category;
1409
1438
  using difference_type =
1410
1439
  typename std::iterator_traits<Iterator>::difference_type;
1411
1440
  using value_type =
@@ -1415,24 +1444,100 @@ class WrappedIterator {
1415
1444
  using pointer =
1416
1445
  std::conditional_t<std::is_void_v<ElementType>,
1417
1446
  typename std::iterator_traits<Iterator>::pointer,
1418
- ElementType*>;
1447
+ std::add_pointer_t<ElementType>>;
1419
1448
  using reference =
1420
1449
  std::conditional_t<std::is_void_v<ElementType>,
1421
1450
  typename std::iterator_traits<Iterator>::reference,
1422
- ElementType&>;
1451
+ std::add_lvalue_reference_t<ElementType>>;
1452
+ using iterator_category =
1453
+ typename std::iterator_traits<Iterator>::iterator_category;
1423
1454
 
1424
- constexpr WrappedIterator() noexcept : it_() {}
1455
+ constexpr WrappedIterator() noexcept = default;
1425
1456
  constexpr explicit WrappedIterator(Iterator it) noexcept : it_(it) {}
1426
1457
 
1458
+ // TODO(pkasting): Switch to `requires` and concepts after dropping support
1459
+ // for old gcc and libstdc++ versions.
1427
1460
  template <typename OtherIterator, typename OtherElementType,
1428
- std::enable_if_t<std::is_convertible_v<OtherIterator, Iterator>,
1429
- bool> = true>
1461
+ typename = std::enable_if_t<
1462
+ std::is_convertible_v<OtherIterator, Iterator>>>
1430
1463
  constexpr WrappedIterator(
1431
- const WrappedIterator<OtherIterator, OtherElementType>& it) noexcept
1432
- : it_(it.base()) {}
1464
+ const WrappedIterator<OtherIterator, OtherElementType>& other) noexcept
1465
+ : it_(other.base()) {}
1466
+
1467
+ [[nodiscard]] constexpr reference operator*() const noexcept { return *it_; }
1468
+ [[nodiscard]] constexpr pointer operator->() const noexcept {
1469
+ if constexpr (std::is_pointer_v<Iterator>) {
1470
+ return it_;
1471
+ } else {
1472
+ return it_.operator->();
1473
+ }
1474
+ }
1475
+
1476
+ template <typename OtherIterator, typename OtherElementType>
1477
+ [[nodiscard]] constexpr bool operator==(
1478
+ const WrappedIterator<OtherIterator, OtherElementType>& other)
1479
+ const noexcept {
1480
+ return it_ == other.base();
1481
+ }
1482
+ #if V8_HAVE_SPACESHIP_OPERATOR
1483
+ template <typename OtherIterator, typename OtherElementType>
1484
+ [[nodiscard]] constexpr auto operator<=>(
1485
+ const WrappedIterator<OtherIterator, OtherElementType>& other)
1486
+ const noexcept {
1487
+ if constexpr (std::three_way_comparable_with<Iterator, OtherIterator>) {
1488
+ return it_ <=> other.base();
1489
+ } else if constexpr (std::totally_ordered_with<Iterator, OtherIterator>) {
1490
+ if (it_ < other.base()) {
1491
+ return std::strong_ordering::less;
1492
+ }
1493
+ return (it_ > other.base()) ? std::strong_ordering::greater
1494
+ : std::strong_ordering::equal;
1495
+ } else {
1496
+ if (it_ < other.base()) {
1497
+ return std::partial_ordering::less;
1498
+ }
1499
+ if (other.base() < it_) {
1500
+ return std::partial_ordering::greater;
1501
+ }
1502
+ return (it_ == other.base()) ? std::partial_ordering::equivalent
1503
+ : std::partial_ordering::unordered;
1504
+ }
1505
+ }
1506
+ #else
1507
+ // Assume that if spaceship isn't present, operator rewriting might not be
1508
+ // either.
1509
+ template <typename OtherIterator, typename OtherElementType>
1510
+ [[nodiscard]] constexpr bool operator!=(
1511
+ const WrappedIterator<OtherIterator, OtherElementType>& other)
1512
+ const noexcept {
1513
+ return it_ != other.base();
1514
+ }
1433
1515
 
1434
- constexpr reference operator*() const noexcept { return *it_; }
1435
- constexpr pointer operator->() const noexcept { return it_.operator->(); }
1516
+ template <typename OtherIterator, typename OtherElementType>
1517
+ [[nodiscard]] constexpr bool operator<(
1518
+ const WrappedIterator<OtherIterator, OtherElementType>& other)
1519
+ const noexcept {
1520
+ return it_ < other.base();
1521
+ }
1522
+ template <typename OtherIterator, typename OtherElementType>
1523
+ [[nodiscard]] constexpr bool operator<=(
1524
+ const WrappedIterator<OtherIterator, OtherElementType>& other)
1525
+ const noexcept {
1526
+ return it_ <= other.base();
1527
+ }
1528
+ template <typename OtherIterator, typename OtherElementType>
1529
+ [[nodiscard]] constexpr bool operator>(
1530
+ const WrappedIterator<OtherIterator, OtherElementType>& other)
1531
+ const noexcept {
1532
+ return it_ > other.base();
1533
+ }
1534
+ template <typename OtherIterator, typename OtherElementType>
1535
+ [[nodiscard]] constexpr bool operator>=(
1536
+ const WrappedIterator<OtherIterator, OtherElementType>& other)
1537
+ const noexcept {
1538
+ return it_ >= other.base();
1539
+ }
1540
+ #endif
1436
1541
 
1437
1542
  constexpr WrappedIterator& operator++() noexcept {
1438
1543
  ++it_;
@@ -1453,116 +1558,68 @@ class WrappedIterator {
1453
1558
  --(*this);
1454
1559
  return result;
1455
1560
  }
1456
- constexpr WrappedIterator operator+(difference_type n) const noexcept {
1561
+ [[nodiscard]] constexpr WrappedIterator operator+(
1562
+ difference_type n) const noexcept {
1457
1563
  WrappedIterator result(*this);
1458
1564
  result += n;
1459
1565
  return result;
1460
1566
  }
1567
+ [[nodiscard]] friend constexpr WrappedIterator operator+(
1568
+ difference_type n, const WrappedIterator& x) noexcept {
1569
+ return x + n;
1570
+ }
1461
1571
  constexpr WrappedIterator& operator+=(difference_type n) noexcept {
1462
1572
  it_ += n;
1463
1573
  return *this;
1464
1574
  }
1465
- constexpr WrappedIterator operator-(difference_type n) const noexcept {
1466
- return *this + (-n);
1575
+ [[nodiscard]] constexpr WrappedIterator operator-(
1576
+ difference_type n) const noexcept {
1577
+ return *this + -n;
1467
1578
  }
1468
1579
  constexpr WrappedIterator& operator-=(difference_type n) noexcept {
1469
- *this += -n;
1470
- return *this;
1580
+ return *this += -n;
1471
1581
  }
1472
- constexpr reference operator[](difference_type n) const noexcept {
1582
+ template <typename OtherIterator, typename OtherElementType>
1583
+ [[nodiscard]] constexpr auto operator-(
1584
+ const WrappedIterator<OtherIterator, OtherElementType>& other)
1585
+ const noexcept {
1586
+ return it_ - other.base();
1587
+ }
1588
+ [[nodiscard]] constexpr reference operator[](
1589
+ difference_type n) const noexcept {
1473
1590
  return it_[n];
1474
1591
  }
1475
1592
 
1476
- constexpr Iterator base() const noexcept { return it_; }
1477
-
1478
- private:
1479
- template <typename OtherIterator, typename OtherElementType>
1480
- friend class WrappedIterator;
1593
+ [[nodiscard]] constexpr const Iterator& base() const noexcept { return it_; }
1481
1594
 
1482
1595
  private:
1483
1596
  Iterator it_;
1484
1597
  };
1485
1598
 
1486
- template <typename Iterator, typename ElementType, typename OtherIterator,
1487
- typename OtherElementType>
1488
- constexpr bool operator==(
1489
- const WrappedIterator<Iterator, ElementType>& x,
1490
- const WrappedIterator<OtherIterator, OtherElementType>& y) noexcept {
1491
- return x.base() == y.base();
1492
- }
1493
-
1494
- template <typename Iterator, typename ElementType, typename OtherIterator,
1495
- typename OtherElementType>
1496
- constexpr bool operator<(
1497
- const WrappedIterator<Iterator, ElementType>& x,
1498
- const WrappedIterator<OtherIterator, OtherElementType>& y) noexcept {
1499
- return x.base() < y.base();
1500
- }
1501
-
1502
- template <typename Iterator, typename ElementType, typename OtherIterator,
1503
- typename OtherElementType>
1504
- constexpr bool operator!=(
1505
- const WrappedIterator<Iterator, ElementType>& x,
1506
- const WrappedIterator<OtherIterator, OtherElementType>& y) noexcept {
1507
- return !(x == y);
1508
- }
1509
-
1510
- template <typename Iterator, typename ElementType, typename OtherIterator,
1511
- typename OtherElementType>
1512
- constexpr bool operator>(
1513
- const WrappedIterator<Iterator, ElementType>& x,
1514
- const WrappedIterator<OtherIterator, OtherElementType>& y) noexcept {
1515
- return y < x;
1516
- }
1517
-
1518
- template <typename Iterator, typename ElementType, typename OtherIterator,
1519
- typename OtherElementType>
1520
- constexpr bool operator>=(
1521
- const WrappedIterator<Iterator, ElementType>& x,
1522
- const WrappedIterator<OtherIterator, OtherElementType>& y) noexcept {
1523
- return !(x < y);
1524
- }
1525
-
1526
- template <typename Iterator, typename ElementType, typename OtherIterator,
1527
- typename OtherElementType>
1528
- constexpr bool operator<=(
1529
- const WrappedIterator<Iterator, ElementType>& x,
1530
- const WrappedIterator<OtherIterator, OtherElementType>& y) noexcept {
1531
- return !(y < x);
1532
- }
1533
-
1534
- template <typename Iterator, typename ElementType, typename OtherIterator,
1535
- typename OtherElementType>
1536
- constexpr auto operator-(
1537
- const WrappedIterator<Iterator, ElementType>& x,
1538
- const WrappedIterator<OtherIterator, OtherElementType>& y) noexcept
1539
- -> decltype(x.base() - y.base()) {
1540
- return x.base() - y.base();
1541
- }
1542
-
1543
- template <typename Iterator, typename ElementType>
1544
- constexpr WrappedIterator<Iterator> operator+(
1545
- typename WrappedIterator<Iterator, ElementType>::difference_type n,
1546
- const WrappedIterator<Iterator, ElementType>& x) noexcept {
1547
- x += n;
1548
- return x;
1549
- }
1550
-
1551
1599
  // Helper functions about values contained in handles.
1552
1600
  // A value is either an indirect pointer or a direct pointer, depending on
1553
1601
  // whether direct local support is enabled.
1554
1602
  class ValueHelper final {
1555
1603
  public:
1604
+ // ValueHelper::InternalRepresentationType is an abstract type that
1605
+ // corresponds to the internal representation of v8::Local and essentially
1606
+ // to what T* really is (these two are always in sync). This type is used in
1607
+ // methods like GetDataFromSnapshotOnce that need access to a handle's
1608
+ // internal representation. In particular, if `x` is a `v8::Local<T>`, then
1609
+ // `v8::Local<T>::FromRepr(x.repr())` gives exactly the same handle as `x`.
1556
1610
  #ifdef V8_ENABLE_DIRECT_HANDLE
1557
1611
  static constexpr Address kTaggedNullAddress = 1;
1558
- static constexpr Address kEmpty = kTaggedNullAddress;
1612
+
1613
+ using InternalRepresentationType = internal::Address;
1614
+ static constexpr InternalRepresentationType kEmpty = kTaggedNullAddress;
1559
1615
  #else
1560
- static constexpr Address kEmpty = kNullAddress;
1616
+ using InternalRepresentationType = internal::Address*;
1617
+ static constexpr InternalRepresentationType kEmpty = nullptr;
1561
1618
  #endif // V8_ENABLE_DIRECT_HANDLE
1562
1619
 
1563
1620
  template <typename T>
1564
1621
  V8_INLINE static bool IsEmpty(T* value) {
1565
- return reinterpret_cast<Address>(value) == kEmpty;
1622
+ return ValueAsRepr(value) == kEmpty;
1566
1623
  }
1567
1624
 
1568
1625
  // Returns a handle's "value" for all kinds of abstract handles. For Local,
@@ -1589,6 +1646,16 @@ class ValueHelper final {
1589
1646
  return *reinterpret_cast<T**>(slot);
1590
1647
  }
1591
1648
 
1649
+ template <typename T>
1650
+ V8_INLINE static InternalRepresentationType ValueAsRepr(const T* value) {
1651
+ return reinterpret_cast<InternalRepresentationType>(value);
1652
+ }
1653
+
1654
+ template <typename T>
1655
+ V8_INLINE static T* ReprAsValue(InternalRepresentationType repr) {
1656
+ return reinterpret_cast<T*>(repr);
1657
+ }
1658
+
1592
1659
  #else // !V8_ENABLE_DIRECT_HANDLE
1593
1660
 
1594
1661
  template <typename T>
@@ -1601,6 +1668,17 @@ class ValueHelper final {
1601
1668
  return reinterpret_cast<T*>(slot);
1602
1669
  }
1603
1670
 
1671
+ template <typename T>
1672
+ V8_INLINE static InternalRepresentationType ValueAsRepr(const T* value) {
1673
+ return const_cast<InternalRepresentationType>(
1674
+ reinterpret_cast<const Address*>(value));
1675
+ }
1676
+
1677
+ template <typename T>
1678
+ V8_INLINE static T* ReprAsValue(InternalRepresentationType repr) {
1679
+ return reinterpret_cast<T*>(repr);
1680
+ }
1681
+
1604
1682
  #endif // V8_ENABLE_DIRECT_HANDLE
1605
1683
  };
1606
1684