1 // Copyright 2018 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef INCLUDE_V8_INTERNAL_H_ 6 #define INCLUDE_V8_INTERNAL_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 #include <string.h> 11 #include <type_traits> 12 13 #include "v8-version.h" // NOLINT(build/include_directory) 14 #include "v8config.h" // NOLINT(build/include_directory) 15 16 namespace v8 { 17 18 class Array; 19 class Context; 20 class Data; 21 class Isolate; 22 template <typename T> 23 class Local; 24 25 namespace internal { 26 27 class Isolate; 28 29 typedef uintptr_t Address; 30 static const Address kNullAddress = 0; 31 32 /** 33 * Configuration of tagging scheme. 34 */ 35 const int kApiSystemPointerSize = sizeof(void*); 36 const int kApiDoubleSize = sizeof(double); 37 const int kApiInt32Size = sizeof(int32_t); 38 const int kApiInt64Size = sizeof(int64_t); 39 const int kApiSizetSize = sizeof(size_t); 40 41 // Tag information for HeapObject. 42 const int kHeapObjectTag = 1; 43 const int kWeakHeapObjectTag = 3; 44 const int kHeapObjectTagSize = 2; 45 const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1; 46 47 // Tag information for fowarding pointers stored in object headers. 48 // 0b00 at the lowest 2 bits in the header indicates that the map word is a 49 // forwarding pointer. 50 const int kForwardingTag = 0; 51 const int kForwardingTagSize = 2; 52 const intptr_t kForwardingTagMask = (1 << kForwardingTagSize) - 1; 53 54 // Tag information for Smi. 55 const int kSmiTag = 0; 56 const int kSmiTagSize = 1; 57 const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1; 58 59 template <size_t tagged_ptr_size> 60 struct SmiTagging; 61 62 constexpr intptr_t kIntptrAllBitsSet = intptr_t{-1}; 63 constexpr uintptr_t kUintptrAllBitsSet = 64 static_cast<uintptr_t>(kIntptrAllBitsSet); 65 66 // Smi constants for systems where tagged pointer is a 32-bit value. 67 template <> 68 struct SmiTagging<4> { 69 enum { kSmiShiftSize = 0, kSmiValueSize = 31 }; 70 71 static constexpr intptr_t kSmiMinValue = 72 static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1)); 73 static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1); 74 75 V8_INLINE static int SmiToInt(const internal::Address value) { 76 int shift_bits = kSmiTagSize + kSmiShiftSize; 77 // Truncate and shift down (requires >> to be sign extending). 78 return static_cast<int32_t>(static_cast<uint32_t>(value)) >> shift_bits; 79 } 80 V8_INLINE static constexpr bool IsValidSmi(intptr_t value) { 81 // Is value in range [kSmiMinValue, kSmiMaxValue]. 82 // Use unsigned operations in order to avoid undefined behaviour in case of 83 // signed integer overflow. 84 return (static_cast<uintptr_t>(value) - 85 static_cast<uintptr_t>(kSmiMinValue)) <= 86 (static_cast<uintptr_t>(kSmiMaxValue) - 87 static_cast<uintptr_t>(kSmiMinValue)); 88 } 89 }; 90 91 // Smi constants for systems where tagged pointer is a 64-bit value. 92 template <> 93 struct SmiTagging<8> { 94 enum { kSmiShiftSize = 31, kSmiValueSize = 32 }; 95 96 static constexpr intptr_t kSmiMinValue = 97 static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1)); 98 static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1); 99 100 V8_INLINE static int SmiToInt(const internal::Address value) { 101 int shift_bits = kSmiTagSize + kSmiShiftSize; 102 // Shift down and throw away top 32 bits. 103 return static_cast<int>(static_cast<intptr_t>(value) >> shift_bits); 104 } 105 V8_INLINE static constexpr bool IsValidSmi(intptr_t value) { 106 // To be representable as a long smi, the value must be a 32-bit integer. 107 return (value == static_cast<int32_t>(value)); 108 } 109 }; 110 111 #ifdef V8_COMPRESS_POINTERS 112 static_assert( 113 kApiSystemPointerSize == kApiInt64Size, 114 "Pointer compression can be enabled only for 64-bit architectures"); 115 const int kApiTaggedSize = kApiInt32Size; 116 #else 117 const int kApiTaggedSize = kApiSystemPointerSize; 118 #endif 119 120 constexpr bool PointerCompressionIsEnabled() { 121 return kApiTaggedSize != kApiSystemPointerSize; 122 } 123 124 constexpr bool HeapSandboxIsEnabled() { 125 #ifdef V8_HEAP_SANDBOX 126 return true; 127 #else 128 return false; 129 #endif 130 } 131 132 using ExternalPointer_t = Address; 133 134 // If the heap sandbox is enabled, these tag values will be ORed with the 135 // external pointers in the external pointer table to prevent use of pointers of 136 // the wrong type. When a pointer is loaded, it is ANDed with the inverse of the 137 // expected type's tag. The tags are constructed in a way that guarantees that a 138 // failed type check will result in one or more of the top bits of the pointer 139 // to be set, rendering the pointer inacessible. This construction allows 140 // performing the type check and removing GC marking bits from the pointer at 141 // the same time. 142 enum ExternalPointerTag : uint64_t { 143 kExternalPointerNullTag = 0x0000000000000000, 144 kExternalStringResourceTag = 0x00ff000000000000, // 0b000000011111111 145 kExternalStringResourceDataTag = 0x017f000000000000, // 0b000000101111111 146 kForeignForeignAddressTag = 0x01bf000000000000, // 0b000000110111111 147 kNativeContextMicrotaskQueueTag = 0x01df000000000000, // 0b000000111011111 148 kEmbedderDataSlotPayloadTag = 0x01ef000000000000, // 0b000000111101111 149 kCodeEntryPointTag = 0x01f7000000000000, // 0b000000111110111 150 }; 151 152 constexpr uint64_t kExternalPointerTagMask = 0xffff000000000000; 153 154 #ifdef V8_31BIT_SMIS_ON_64BIT_ARCH 155 using PlatformSmiTagging = SmiTagging<kApiInt32Size>; 156 #else 157 using PlatformSmiTagging = SmiTagging<kApiTaggedSize>; 158 #endif 159 160 // TODO(ishell): Consinder adding kSmiShiftBits = kSmiShiftSize + kSmiTagSize 161 // since it's used much more often than the inividual constants. 162 const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize; 163 const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize; 164 const int kSmiMinValue = static_cast<int>(PlatformSmiTagging::kSmiMinValue); 165 const int kSmiMaxValue = static_cast<int>(PlatformSmiTagging::kSmiMaxValue); 166 constexpr bool SmiValuesAre31Bits() { return kSmiValueSize == 31; } 167 constexpr bool SmiValuesAre32Bits() { return kSmiValueSize == 32; } 168 169 V8_INLINE static constexpr internal::Address IntToSmi(int value) { 170 return (static_cast<Address>(value) << (kSmiTagSize + kSmiShiftSize)) | 171 kSmiTag; 172 } 173 174 // Converts encoded external pointer to address. 175 V8_EXPORT Address DecodeExternalPointerImpl(const Isolate* isolate, 176 ExternalPointer_t pointer, 177 ExternalPointerTag tag); 178 179 // {obj} must be the raw tagged pointer representation of a HeapObject 180 // that's guaranteed to never be in ReadOnlySpace. 181 V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj); 182 183 // Returns if we need to throw when an error occurs. This infers the language 184 // mode based on the current context and the closure. This returns true if the 185 // language mode is strict. 186 V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate); 187 188 V8_EXPORT bool CanHaveInternalField(int instance_type); 189 190 /** 191 * This class exports constants and functionality from within v8 that 192 * is necessary to implement inline functions in the v8 api. Don't 193 * depend on functions and constants defined here. 194 */ 195 class Internals { 196 #ifdef V8_MAP_PACKING 197 V8_INLINE static constexpr internal::Address UnpackMapWord( 198 internal::Address mapword) { 199 // TODO(wenyuzhao): Clear header metadata. 200 return mapword ^ kMapWordXorMask; 201 } 202 #endif 203 204 public: 205 // These values match non-compiler-dependent values defined within 206 // the implementation of v8. 207 static const int kHeapObjectMapOffset = 0; 208 static const int kMapInstanceTypeOffset = 1 * kApiTaggedSize + kApiInt32Size; 209 static const int kStringResourceOffset = 210 1 * kApiTaggedSize + 2 * kApiInt32Size; 211 212 static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize; 213 static const int kJSObjectHeaderSize = 3 * kApiTaggedSize; 214 static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize; 215 static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize; 216 static const int kEmbedderDataSlotSize = kApiSystemPointerSize; 217 #ifdef V8_HEAP_SANDBOX 218 static const int kEmbedderDataSlotRawPayloadOffset = kApiTaggedSize; 219 #endif 220 static const int kNativeContextEmbedderDataOffset = 6 * kApiTaggedSize; 221 static const int kFullStringRepresentationMask = 0x0f; 222 static const int kStringEncodingMask = 0x8; 223 static const int kExternalTwoByteRepresentationTag = 0x02; 224 static const int kExternalOneByteRepresentationTag = 0x0a; 225 226 static const uint32_t kNumIsolateDataSlots = 4; 227 static const int kStackGuardSize = 7 * kApiSystemPointerSize; 228 static const int kBuiltinTier0EntryTableSize = 13 * kApiSystemPointerSize; 229 static const int kBuiltinTier0TableSize = 13 * kApiSystemPointerSize; 230 231 // IsolateData layout guarantees. 232 static const int kIsolateCageBaseOffset = 0; 233 static const int kIsolateStackGuardOffset = 234 kIsolateCageBaseOffset + kApiSystemPointerSize; 235 static const int kBuiltinTier0EntryTableOffset = 236 kIsolateStackGuardOffset + kStackGuardSize; 237 static const int kBuiltinTier0TableOffset = 238 kBuiltinTier0EntryTableOffset + kBuiltinTier0EntryTableSize; 239 static const int kIsolateEmbedderDataOffset = 240 kBuiltinTier0TableOffset + kBuiltinTier0TableSize; 241 static const int kIsolateFastCCallCallerFpOffset = 242 kIsolateEmbedderDataOffset + kNumIsolateDataSlots * kApiSystemPointerSize; 243 static const int kIsolateFastCCallCallerPcOffset = 244 kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize; 245 static const int kIsolateFastApiCallTargetOffset = 246 kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize; 247 static const int kIsolateLongTaskStatsCounterOffset = 248 kIsolateFastApiCallTargetOffset + kApiSystemPointerSize; 249 static const int kIsolateRootsOffset = 250 kIsolateLongTaskStatsCounterOffset + kApiSizetSize; 251 252 static const int kExternalPointerTableBufferOffset = 0; 253 static const int kExternalPointerTableLengthOffset = 254 kExternalPointerTableBufferOffset + kApiSystemPointerSize; 255 static const int kExternalPointerTableCapacityOffset = 256 kExternalPointerTableLengthOffset + kApiInt32Size; 257 258 static const int kUndefinedValueRootIndex = 4; 259 static const int kTheHoleValueRootIndex = 5; 260 static const int kNullValueRootIndex = 6; 261 static const int kTrueValueRootIndex = 7; 262 static const int kFalseValueRootIndex = 8; 263 static const int kEmptyStringRootIndex = 9; 264 265 static const int kNodeClassIdOffset = 1 * kApiSystemPointerSize; 266 static const int kNodeFlagsOffset = 1 * kApiSystemPointerSize + 3; 267 static const int kNodeStateMask = 0x7; 268 static const int kNodeStateIsWeakValue = 2; 269 static const int kNodeStateIsPendingValue = 3; 270 271 static const int kFirstNonstringType = 0x40; 272 static const int kOddballType = 0x43; 273 static const int kForeignType = 0x46; 274 static const int kJSSpecialApiObjectType = 0x410; 275 static const int kJSObjectType = 0x421; 276 static const int kFirstJSApiObjectType = 0x422; 277 static const int kLastJSApiObjectType = 0x80A; 278 279 static const int kUndefinedOddballKind = 5; 280 static const int kNullOddballKind = 3; 281 282 // Constants used by PropertyCallbackInfo to check if we should throw when an 283 // error occurs. 284 static const int kThrowOnError = 0; 285 static const int kDontThrow = 1; 286 static const int kInferShouldThrowMode = 2; 287 288 // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an 289 // incremental GC once the external memory reaches this limit. 290 static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024; 291 292 #ifdef V8_MAP_PACKING 293 static const uintptr_t kMapWordMetadataMask = 0xffffULL << 48; 294 // The lowest two bits of mapwords are always `0b10` 295 static const uintptr_t kMapWordSignature = 0b10; 296 // XORing a (non-compressed) map with this mask ensures that the two 297 // low-order bits are 0b10. The 0 at the end makes this look like a Smi, 298 // although real Smis have all lower 32 bits unset. We only rely on these 299 // values passing as Smis in very few places. 300 static const int kMapWordXorMask = 0b11; 301 #endif 302 303 V8_EXPORT static void CheckInitializedImpl(v8::Isolate* isolate); 304 V8_INLINE static void CheckInitialized(v8::Isolate* isolate) { 305 #ifdef V8_ENABLE_CHECKS 306 CheckInitializedImpl(isolate); 307 #endif 308 } 309 310 V8_INLINE static bool HasHeapObjectTag(const internal::Address value) { 311 return (value & kHeapObjectTagMask) == static_cast<Address>(kHeapObjectTag); 312 } 313 314 V8_INLINE static int SmiValue(const internal::Address value) { 315 return PlatformSmiTagging::SmiToInt(value); 316 } 317 318 V8_INLINE static constexpr internal::Address IntToSmi(int value) { 319 return internal::IntToSmi(value); 320 } 321 322 V8_INLINE static constexpr bool IsValidSmi(intptr_t value) { 323 return PlatformSmiTagging::IsValidSmi(value); 324 } 325 326 V8_INLINE static int GetInstanceType(const internal::Address obj) { 327 typedef internal::Address A; 328 A map = ReadTaggedPointerField(obj, kHeapObjectMapOffset); 329 #ifdef V8_MAP_PACKING 330 map = UnpackMapWord(map); 331 #endif 332 return ReadRawField<uint16_t>(map, kMapInstanceTypeOffset); 333 } 334 335 V8_INLINE static int GetOddballKind(const internal::Address obj) { 336 return SmiValue(ReadTaggedSignedField(obj, kOddballKindOffset)); 337 } 338 339 V8_INLINE static bool IsExternalTwoByteString(int instance_type) { 340 int representation = (instance_type & kFullStringRepresentationMask); 341 return representation == kExternalTwoByteRepresentationTag; 342 } 343 344 V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) { 345 uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset; 346 return *addr & static_cast<uint8_t>(1U << shift); 347 } 348 349 V8_INLINE static void UpdateNodeFlag(internal::Address* obj, bool value, 350 int shift) { 351 uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset; 352 uint8_t mask = static_cast<uint8_t>(1U << shift); 353 *addr = static_cast<uint8_t>((*addr & ~mask) | (value << shift)); 354 } 355 356 V8_INLINE static uint8_t GetNodeState(internal::Address* obj) { 357 uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset; 358 return *addr & kNodeStateMask; 359 } 360 361 V8_INLINE static void UpdateNodeState(internal::Address* obj, uint8_t value) { 362 uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset; 363 *addr = static_cast<uint8_t>((*addr & ~kNodeStateMask) | value); 364 } 365 366 V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, uint32_t slot, 367 void* data) { 368 internal::Address addr = reinterpret_cast<internal::Address>(isolate) + 369 kIsolateEmbedderDataOffset + 370 slot * kApiSystemPointerSize; 371 *reinterpret_cast<void**>(addr) = data; 372 } 373 374 V8_INLINE static void* GetEmbedderData(const v8::Isolate* isolate, 375 uint32_t slot) { 376 internal::Address addr = reinterpret_cast<internal::Address>(isolate) + 377 kIsolateEmbedderDataOffset + 378 slot * kApiSystemPointerSize; 379 return *reinterpret_cast<void* const*>(addr); 380 } 381 382 V8_INLINE static void IncrementLongTasksStatsCounter(v8::Isolate* isolate) { 383 internal::Address addr = reinterpret_cast<internal::Address>(isolate) + 384 kIsolateLongTaskStatsCounterOffset; 385 ++(*reinterpret_cast<size_t*>(addr)); 386 } 387 388 V8_INLINE static internal::Address* GetRoot(v8::Isolate* isolate, int index) { 389 internal::Address addr = reinterpret_cast<internal::Address>(isolate) + 390 kIsolateRootsOffset + 391 index * kApiSystemPointerSize; 392 return reinterpret_cast<internal::Address*>(addr); 393 } 394 395 template <typename T> 396 V8_INLINE static T ReadRawField(internal::Address heap_object_ptr, 397 int offset) { 398 internal::Address addr = heap_object_ptr + offset - kHeapObjectTag; 399 #ifdef V8_COMPRESS_POINTERS 400 if (sizeof(T) > kApiTaggedSize) { 401 // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size 402 // fields (external pointers, doubles and BigInt data) are only 403 // kTaggedSize aligned so we have to use unaligned pointer friendly way of 404 // accessing them in order to avoid undefined behavior in C++ code. 405 T r; 406 memcpy(&r, reinterpret_cast<void*>(addr), sizeof(T)); 407 return r; 408 } 409 #endif 410 return *reinterpret_cast<const T*>(addr); 411 } 412 413 V8_INLINE static internal::Address ReadTaggedPointerField( 414 internal::Address heap_object_ptr, int offset) { 415 #ifdef V8_COMPRESS_POINTERS 416 uint32_t value = ReadRawField<uint32_t>(heap_object_ptr, offset); 417 internal::Address base = 418 GetPtrComprCageBaseFromOnHeapAddress(heap_object_ptr); 419 return base + static_cast<internal::Address>(static_cast<uintptr_t>(value)); 420 #else 421 return ReadRawField<internal::Address>(heap_object_ptr, offset); 422 #endif 423 } 424 425 V8_INLINE static internal::Address ReadTaggedSignedField( 426 internal::Address heap_object_ptr, int offset) { 427 #ifdef V8_COMPRESS_POINTERS 428 uint32_t value = ReadRawField<uint32_t>(heap_object_ptr, offset); 429 return static_cast<internal::Address>(static_cast<uintptr_t>(value)); 430 #else 431 return ReadRawField<internal::Address>(heap_object_ptr, offset); 432 #endif 433 } 434 435 V8_INLINE static internal::Isolate* GetIsolateForHeapSandbox( 436 internal::Address obj) { 437 #ifdef V8_HEAP_SANDBOX 438 return internal::IsolateFromNeverReadOnlySpaceObject(obj); 439 #else 440 // Not used in non-sandbox mode. 441 return nullptr; 442 #endif 443 } 444 445 V8_INLINE static Address DecodeExternalPointer( 446 const Isolate* isolate, ExternalPointer_t encoded_pointer, 447 ExternalPointerTag tag) { 448 #ifdef V8_HEAP_SANDBOX 449 return internal::DecodeExternalPointerImpl(isolate, encoded_pointer, tag); 450 #else 451 return encoded_pointer; 452 #endif 453 } 454 455 V8_INLINE static internal::Address ReadExternalPointerField( 456 internal::Isolate* isolate, internal::Address heap_object_ptr, int offset, 457 ExternalPointerTag tag) { 458 #ifdef V8_HEAP_SANDBOX 459 internal::ExternalPointer_t encoded_value = 460 ReadRawField<uint32_t>(heap_object_ptr, offset); 461 // We currently have to treat zero as nullptr in embedder slots. 462 return encoded_value ? DecodeExternalPointer(isolate, encoded_value, tag) 463 : 0; 464 #else 465 return ReadRawField<Address>(heap_object_ptr, offset); 466 #endif 467 } 468 469 #ifdef V8_COMPRESS_POINTERS 470 // See v8:7703 or src/ptr-compr.* for details about pointer compression. 471 static constexpr size_t kPtrComprCageReservationSize = size_t{1} << 32; 472 static constexpr size_t kPtrComprCageBaseAlignment = size_t{1} << 32; 473 474 V8_INLINE static internal::Address GetPtrComprCageBaseFromOnHeapAddress( 475 internal::Address addr) { 476 return addr & -static_cast<intptr_t>(kPtrComprCageBaseAlignment); 477 } 478 479 V8_INLINE static internal::Address DecompressTaggedAnyField( 480 internal::Address heap_object_ptr, uint32_t value) { 481 internal::Address base = 482 GetPtrComprCageBaseFromOnHeapAddress(heap_object_ptr); 483 return base + static_cast<internal::Address>(static_cast<uintptr_t>(value)); 484 } 485 486 #endif // V8_COMPRESS_POINTERS 487 }; 488 489 constexpr bool VirtualMemoryCageIsEnabled() { 490 #ifdef V8_VIRTUAL_MEMORY_CAGE 491 return true; 492 #else 493 return false; 494 #endif 495 } 496 497 #ifdef V8_VIRTUAL_MEMORY_CAGE 498 // Size of the virtual memory cage, excluding the guard regions surrounding it. 499 constexpr size_t kVirtualMemoryCageSize = size_t{1} << 40; // 1 TB 500 501 static_assert(kVirtualMemoryCageSize > Internals::kPtrComprCageReservationSize, 502 "The virtual memory cage must be larger than the pointer " 503 "compression cage contained within it."); 504 505 // Required alignment of the virtual memory cage. For simplicity, we require the 506 // size of the guard regions to be a multiple of this, so that this specifies 507 // the alignment of the cage including and excluding surrounding guard regions. 508 // The alignment requirement is due to the pointer compression cage being 509 // located at the start of the virtual memory cage. 510 constexpr size_t kVirtualMemoryCageAlignment = 511 Internals::kPtrComprCageBaseAlignment; 512 513 // Size of the guard regions surrounding the virtual memory cage. This assumes a 514 // worst-case scenario of a 32-bit unsigned index being used to access an array 515 // of 64-bit values. 516 constexpr size_t kVirtualMemoryCageGuardRegionSize = size_t{32} << 30; // 32 GB 517 518 static_assert((kVirtualMemoryCageGuardRegionSize % 519 kVirtualMemoryCageAlignment) == 0, 520 "The size of the virtual memory cage guard region must be a " 521 "multiple of its required alignment."); 522 523 // Minimum size of the virtual memory cage, excluding the guard regions 524 // surrounding it. If the cage reservation fails, its size is currently halved 525 // until either the reservation succeeds or the minimum size is reached. A 526 // minimum of 32GB allows the 4GB pointer compression region as well as the 527 // ArrayBuffer partition and two 10GB WASM memory cages to fit into the cage. 528 constexpr size_t kVirtualMemoryCageMinimumSize = size_t{32} << 30; // 32 GB 529 530 // For now, even if the virtual memory cage is enabled, we still allow backing 531 // stores to be allocated outside of it as fallback. This will simplify the 532 // initial rollout. However, if the heap sandbox is also enabled, we already use 533 // the "enforcing mode" of the virtual memory cage. This is useful for testing. 534 #ifdef V8_HEAP_SANDBOX 535 constexpr bool kAllowBackingStoresOutsideCage = false; 536 #else 537 constexpr bool kAllowBackingStoresOutsideCage = true; 538 #endif // V8_HEAP_SANDBOX 539 540 #endif // V8_VIRTUAL_MEMORY_CAGE 541 542 // Only perform cast check for types derived from v8::Data since 543 // other types do not implement the Cast method. 544 template <bool PerformCheck> 545 struct CastCheck { 546 template <class T> 547 static void Perform(T* data); 548 }; 549 550 template <> 551 template <class T> 552 void CastCheck<true>::Perform(T* data) { 553 T::Cast(data); 554 } 555 556 template <> 557 template <class T> 558 void CastCheck<false>::Perform(T* data) {} 559 560 template <class T> 561 V8_INLINE void PerformCastCheck(T* data) { 562 CastCheck<std::is_base_of<Data, T>::value && 563 !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data); 564 } 565 566 // A base class for backing stores, which is needed due to vagaries of 567 // how static casts work with std::shared_ptr. 568 class BackingStoreBase {}; 569 570 } // namespace internal 571 572 } // namespace v8 573 574 #endif // INCLUDE_V8_INTERNAL_H_ 575