xref: /third_party/node/deps/v8/include/v8-internal.h (revision 1cb0ef41)
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
16namespace v8 {
17
18class Array;
19class Context;
20class Data;
21class Isolate;
22template <typename T>
23class Local;
24
25namespace internal {
26
27class Isolate;
28
29typedef uintptr_t Address;
30static const Address kNullAddress = 0;
31
32constexpr int KB = 1024;
33constexpr int MB = KB * 1024;
34constexpr int GB = MB * 1024;
35#ifdef V8_TARGET_ARCH_X64
36constexpr size_t TB = size_t{GB} * 1024;
37#endif
38
39/**
40 * Configuration of tagging scheme.
41 */
42const int kApiSystemPointerSize = sizeof(void*);
43const int kApiDoubleSize = sizeof(double);
44const int kApiInt32Size = sizeof(int32_t);
45const int kApiInt64Size = sizeof(int64_t);
46const int kApiSizetSize = sizeof(size_t);
47
48// Tag information for HeapObject.
49const int kHeapObjectTag = 1;
50const int kWeakHeapObjectTag = 3;
51const int kHeapObjectTagSize = 2;
52const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1;
53
54// Tag information for fowarding pointers stored in object headers.
55// 0b00 at the lowest 2 bits in the header indicates that the map word is a
56// forwarding pointer.
57const int kForwardingTag = 0;
58const int kForwardingTagSize = 2;
59const intptr_t kForwardingTagMask = (1 << kForwardingTagSize) - 1;
60
61// Tag information for Smi.
62const int kSmiTag = 0;
63const int kSmiTagSize = 1;
64const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1;
65
66template <size_t tagged_ptr_size>
67struct SmiTagging;
68
69constexpr intptr_t kIntptrAllBitsSet = intptr_t{-1};
70constexpr uintptr_t kUintptrAllBitsSet =
71    static_cast<uintptr_t>(kIntptrAllBitsSet);
72
73// Smi constants for systems where tagged pointer is a 32-bit value.
74template <>
75struct SmiTagging<4> {
76  enum { kSmiShiftSize = 0, kSmiValueSize = 31 };
77
78  static constexpr intptr_t kSmiMinValue =
79      static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1));
80  static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1);
81
82  V8_INLINE static int SmiToInt(const internal::Address value) {
83    int shift_bits = kSmiTagSize + kSmiShiftSize;
84    // Truncate and shift down (requires >> to be sign extending).
85    return static_cast<int32_t>(static_cast<uint32_t>(value)) >> shift_bits;
86  }
87  V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
88    // Is value in range [kSmiMinValue, kSmiMaxValue].
89    // Use unsigned operations in order to avoid undefined behaviour in case of
90    // signed integer overflow.
91    return (static_cast<uintptr_t>(value) -
92            static_cast<uintptr_t>(kSmiMinValue)) <=
93           (static_cast<uintptr_t>(kSmiMaxValue) -
94            static_cast<uintptr_t>(kSmiMinValue));
95  }
96};
97
98// Smi constants for systems where tagged pointer is a 64-bit value.
99template <>
100struct SmiTagging<8> {
101  enum { kSmiShiftSize = 31, kSmiValueSize = 32 };
102
103  static constexpr intptr_t kSmiMinValue =
104      static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1));
105  static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1);
106
107  V8_INLINE static int SmiToInt(const internal::Address value) {
108    int shift_bits = kSmiTagSize + kSmiShiftSize;
109    // Shift down and throw away top 32 bits.
110    return static_cast<int>(static_cast<intptr_t>(value) >> shift_bits);
111  }
112  V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
113    // To be representable as a long smi, the value must be a 32-bit integer.
114    return (value == static_cast<int32_t>(value));
115  }
116};
117
118#ifdef V8_COMPRESS_POINTERS
119// See v8:7703 or src/common/ptr-compr-inl.h for details about pointer
120// compression.
121constexpr size_t kPtrComprCageReservationSize = size_t{1} << 32;
122constexpr size_t kPtrComprCageBaseAlignment = size_t{1} << 32;
123
124static_assert(
125    kApiSystemPointerSize == kApiInt64Size,
126    "Pointer compression can be enabled only for 64-bit architectures");
127const int kApiTaggedSize = kApiInt32Size;
128#else
129const int kApiTaggedSize = kApiSystemPointerSize;
130#endif
131
132constexpr bool PointerCompressionIsEnabled() {
133  return kApiTaggedSize != kApiSystemPointerSize;
134}
135
136#ifdef V8_31BIT_SMIS_ON_64BIT_ARCH
137using PlatformSmiTagging = SmiTagging<kApiInt32Size>;
138#else
139using PlatformSmiTagging = SmiTagging<kApiTaggedSize>;
140#endif
141
142// TODO(ishell): Consinder adding kSmiShiftBits = kSmiShiftSize + kSmiTagSize
143// since it's used much more often than the inividual constants.
144const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize;
145const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize;
146const int kSmiMinValue = static_cast<int>(PlatformSmiTagging::kSmiMinValue);
147const int kSmiMaxValue = static_cast<int>(PlatformSmiTagging::kSmiMaxValue);
148constexpr bool SmiValuesAre31Bits() { return kSmiValueSize == 31; }
149constexpr bool SmiValuesAre32Bits() { return kSmiValueSize == 32; }
150
151V8_INLINE static constexpr internal::Address IntToSmi(int value) {
152  return (static_cast<Address>(value) << (kSmiTagSize + kSmiShiftSize)) |
153         kSmiTag;
154}
155
156/*
157 * Sandbox related types, constants, and functions.
158 */
159constexpr bool SandboxIsEnabled() {
160#ifdef V8_SANDBOX
161  return true;
162#else
163  return false;
164#endif
165}
166
167constexpr bool SandboxedExternalPointersAreEnabled() {
168#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
169  return true;
170#else
171  return false;
172#endif
173}
174
175// SandboxedPointers are guaranteed to point into the sandbox. This is achieved
176// for example by storing them as offset rather than as raw pointers.
177using SandboxedPointer_t = Address;
178
179// ExternalPointers point to objects located outside the sandbox. When sandboxed
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
183using ExternalPointer_t = uint32_t;
184#else
185using ExternalPointer_t = Address;
186#endif
187
188#ifdef V8_SANDBOX_IS_AVAILABLE
189
190// Size of the sandbox, excluding the guard regions surrounding it.
191constexpr size_t kSandboxSizeLog2 = 40;  // 1 TB
192constexpr size_t kSandboxSize = 1ULL << kSandboxSizeLog2;
193
194// Required alignment of the sandbox. For simplicity, we require the
195// size of the guard regions to be a multiple of this, so that this specifies
196// the alignment of the sandbox including and excluding surrounding guard
197// regions. The alignment requirement is due to the pointer compression cage
198// being located at the start of the sandbox.
199constexpr size_t kSandboxAlignment = kPtrComprCageBaseAlignment;
200
201// Sandboxed pointers are stored inside the heap as offset from the sandbox
202// base shifted to the left. This way, it is guaranteed that the offset is
203// smaller than the sandbox size after shifting it to the right again. This
204// constant specifies the shift amount.
205constexpr uint64_t kSandboxedPointerShift = 64 - kSandboxSizeLog2;
206
207// Size of the guard regions surrounding the sandbox. This assumes a worst-case
208// scenario of a 32-bit unsigned index used to access an array of 64-bit
209// values.
210constexpr size_t kSandboxGuardRegionSize = 32ULL * GB;
211
212static_assert((kSandboxGuardRegionSize % kSandboxAlignment) == 0,
213              "The size of the guard regions around the sandbox must be a "
214              "multiple of its required alignment.");
215
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.
224constexpr size_t kSandboxMinimumSize = 32ULL * GB;
225
226static_assert(kSandboxMinimumSize <= kSandboxSize,
227              "The minimal size of the sandbox must be smaller or equal to the "
228              "regular size.");
229
230// On OSes where reserving virtual memory is too expensive to reserve the
231// entire address space backing the sandbox, notably Windows pre 8.1, we create
232// a partially reserved sandbox that doesn't actually reserve most of the
233// memory, and so doesn't have the desired security properties as unrelated
234// memory allocations could end up inside of it, but which still ensures that
235// objects that should be located inside the sandbox are allocated within
236// kSandboxSize bytes from the start of the sandbox. The minimum size of the
237// region that is actually reserved for such a sandbox is specified by this
238// constant and should be big enough to contain the pointer compression cage as
239// well as the ArrayBuffer partition.
240constexpr size_t kSandboxMinimumReservationSize = 8ULL * GB;
241
242static_assert(kSandboxMinimumSize > kPtrComprCageReservationSize,
243              "The sandbox must be larger than the pointer compression cage "
244              "contained within it.");
245static_assert(kSandboxMinimumReservationSize > kPtrComprCageReservationSize,
246              "The minimum reservation size for a sandbox must be larger than "
247              "the pointer compression cage contained within it.");
248
249// For now, even if the sandbox is enabled, we still allow backing stores to be
250// allocated outside of it as fallback. This will simplify the initial rollout.
251// However, if sandboxed pointers are also enabled, we must always place
252// backing stores inside the sandbox as they will be referenced though them.
253#ifdef V8_SANDBOXED_POINTERS
254constexpr bool kAllowBackingStoresOutsideSandbox = false;
255#else
256constexpr bool kAllowBackingStoresOutsideSandbox = true;
257#endif  // V8_SANDBOXED_POINTERS
258
259// The size of the virtual memory reservation for an external pointer table.
260// This determines the maximum number of entries in a table. Using a maximum
261// size allows omitting bounds checks on table accesses if the indices are
262// guaranteed (e.g. through shifting) to be below the maximum index. This
263// value must be a power of two.
264static const size_t kExternalPointerTableReservationSize = 128 * MB;
265
266// The maximum number of entries in an external pointer table.
267static const size_t kMaxSandboxedExternalPointers =
268    kExternalPointerTableReservationSize / kApiSystemPointerSize;
269
270// The external pointer table indices stored in HeapObjects as external
271// pointers are shifted to the left by this amount to guarantee that they are
272// smaller than the maximum table size.
273static const uint32_t kExternalPointerIndexShift = 8;
274static_assert((1 << (32 - kExternalPointerIndexShift)) ==
275                  kMaxSandboxedExternalPointers,
276              "kExternalPointerTableReservationSize and "
277              "kExternalPointerIndexShift don't match");
278
279#endif  // V8_SANDBOX_IS_AVAILABLE
280
281// If sandboxed external pointers are enabled, these tag values will be ORed
282// with the external pointers in the external pointer table to prevent use of
283// pointers of the wrong type. When a pointer is loaded, it is ANDed with the
284// inverse of the expected type's tag. The tags are constructed in a way that
285// guarantees that a failed type check will result in one or more of the top
286// bits of the pointer to be set, rendering the pointer inacessible. Besides
287// the type tag bits (48 through 62), the tags also have the GC mark bit (63)
288// set, so that the mark bit is automatically set when a pointer is written
289// into the external pointer table (in which case it is clearly alive) and is
290// cleared when the pointer is loaded. The exception to this is the free entry
291// tag, which doesn't have the mark bit set, as the entry is not alive. This
292// construction allows performing the type check and removing GC marking bits
293// (the MSB) from the pointer at the same time.
294// Note: this scheme assumes a 48-bit address space and will likely break if
295// more virtual address bits are used.
296constexpr uint64_t kExternalPointerTagMask = 0xffff000000000000;
297constexpr uint64_t kExternalPointerTagShift = 48;
298#define MAKE_TAG(v) (static_cast<uint64_t>(v) << kExternalPointerTagShift)
299// clang-format off
300enum ExternalPointerTag : uint64_t {
301  kExternalPointerNullTag =         MAKE_TAG(0b0000000000000000),
302  kExternalPointerFreeEntryTag =    MAKE_TAG(0b0111111110000000),
303  kExternalStringResourceTag =      MAKE_TAG(0b1000000011111111),
304  kExternalStringResourceDataTag =  MAKE_TAG(0b1000000101111111),
305  kForeignForeignAddressTag =       MAKE_TAG(0b1000000110111111),
306  kNativeContextMicrotaskQueueTag = MAKE_TAG(0b1000000111011111),
307  kEmbedderDataSlotPayloadTag =     MAKE_TAG(0b1000000111101111),
308  kCodeEntryPointTag =              MAKE_TAG(0b1000000111110111),
309  kExternalObjectValueTag =         MAKE_TAG(0b1000000111111011),
310};
311// clang-format on
312#undef MAKE_TAG
313
314// Converts encoded external pointer to address.
315V8_EXPORT Address DecodeExternalPointerImpl(const Isolate* isolate,
316                                            ExternalPointer_t pointer,
317                                            ExternalPointerTag tag);
318
319// {obj} must be the raw tagged pointer representation of a HeapObject
320// that's guaranteed to never be in ReadOnlySpace.
321V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);
322
323// Returns if we need to throw when an error occurs. This infers the language
324// mode based on the current context and the closure. This returns true if the
325// language mode is strict.
326V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate);
327
328V8_EXPORT bool CanHaveInternalField(int instance_type);
329
330/**
331 * This class exports constants and functionality from within v8 that
332 * is necessary to implement inline functions in the v8 api.  Don't
333 * depend on functions and constants defined here.
334 */
335class Internals {
336#ifdef V8_MAP_PACKING
337  V8_INLINE static constexpr internal::Address UnpackMapWord(
338      internal::Address mapword) {
339    // TODO(wenyuzhao): Clear header metadata.
340    return mapword ^ kMapWordXorMask;
341  }
342#endif
343
344 public:
345  // These values match non-compiler-dependent values defined within
346  // the implementation of v8.
347  static const int kHeapObjectMapOffset = 0;
348  static const int kMapInstanceTypeOffset = 1 * kApiTaggedSize + kApiInt32Size;
349  static const int kStringResourceOffset =
350      1 * kApiTaggedSize + 2 * kApiInt32Size;
351
352  static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize;
353  static const int kJSObjectHeaderSize = 3 * kApiTaggedSize;
354  static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize;
355  static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize;
356  static const int kEmbedderDataSlotSize = kApiSystemPointerSize;
357#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
358  static const int kEmbedderDataSlotRawPayloadOffset = kApiTaggedSize;
359#endif
360  static const int kNativeContextEmbedderDataOffset = 6 * kApiTaggedSize;
361  static const int kStringRepresentationAndEncodingMask = 0x0f;
362  static const int kStringEncodingMask = 0x8;
363  static const int kExternalTwoByteRepresentationTag = 0x02;
364  static const int kExternalOneByteRepresentationTag = 0x0a;
365
366  static const uint32_t kNumIsolateDataSlots = 4;
367  static const int kStackGuardSize = 7 * kApiSystemPointerSize;
368  static const int kBuiltinTier0EntryTableSize = 10 * kApiSystemPointerSize;
369  static const int kBuiltinTier0TableSize = 10 * kApiSystemPointerSize;
370
371  // IsolateData layout guarantees.
372  static const int kIsolateCageBaseOffset = 0;
373  static const int kIsolateStackGuardOffset =
374      kIsolateCageBaseOffset + kApiSystemPointerSize;
375  static const int kBuiltinTier0EntryTableOffset =
376      kIsolateStackGuardOffset + kStackGuardSize;
377  static const int kBuiltinTier0TableOffset =
378      kBuiltinTier0EntryTableOffset + kBuiltinTier0EntryTableSize;
379  static const int kIsolateEmbedderDataOffset =
380      kBuiltinTier0TableOffset + kBuiltinTier0TableSize;
381  static const int kIsolateFastCCallCallerFpOffset =
382      kIsolateEmbedderDataOffset + kNumIsolateDataSlots * kApiSystemPointerSize;
383  static const int kIsolateFastCCallCallerPcOffset =
384      kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize;
385  static const int kIsolateFastApiCallTargetOffset =
386      kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize;
387  static const int kIsolateLongTaskStatsCounterOffset =
388      kIsolateFastApiCallTargetOffset + kApiSystemPointerSize;
389  static const int kIsolateRootsOffset =
390      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;
397
398  static const int kUndefinedValueRootIndex = 4;
399  static const int kTheHoleValueRootIndex = 5;
400  static const int kNullValueRootIndex = 6;
401  static const int kTrueValueRootIndex = 7;
402  static const int kFalseValueRootIndex = 8;
403  static const int kEmptyStringRootIndex = 9;
404
405  static const int kNodeClassIdOffset = 1 * kApiSystemPointerSize;
406  static const int kNodeFlagsOffset = 1 * kApiSystemPointerSize + 3;
407  static const int kNodeStateMask = 0x7;
408  static const int kNodeStateIsWeakValue = 2;
409  static const int kNodeStateIsPendingValue = 3;
410
411  static const int kFirstNonstringType = 0x80;
412  static const int kOddballType = 0x83;
413  static const int kForeignType = 0xcc;
414  static const int kJSSpecialApiObjectType = 0x410;
415  static const int kJSObjectType = 0x421;
416  static const int kFirstJSApiObjectType = 0x422;
417  static const int kLastJSApiObjectType = 0x80A;
418
419  static const int kUndefinedOddballKind = 5;
420  static const int kNullOddballKind = 3;
421
422  // Constants used by PropertyCallbackInfo to check if we should throw when an
423  // error occurs.
424  static const int kThrowOnError = 0;
425  static const int kDontThrow = 1;
426  static const int kInferShouldThrowMode = 2;
427
428  // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an
429  // incremental GC once the external memory reaches this limit.
430  static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024;
431
432#ifdef V8_MAP_PACKING
433  static const uintptr_t kMapWordMetadataMask = 0xffffULL << 48;
434  // The lowest two bits of mapwords are always `0b10`
435  static const uintptr_t kMapWordSignature = 0b10;
436  // XORing a (non-compressed) map with this mask ensures that the two
437  // low-order bits are 0b10. The 0 at the end makes this look like a Smi,
438  // although real Smis have all lower 32 bits unset. We only rely on these
439  // values passing as Smis in very few places.
440  static const int kMapWordXorMask = 0b11;
441#endif
442
443  V8_EXPORT static void CheckInitializedImpl(v8::Isolate* isolate);
444  V8_INLINE static void CheckInitialized(v8::Isolate* isolate) {
445#ifdef V8_ENABLE_CHECKS
446    CheckInitializedImpl(isolate);
447#endif
448  }
449
450  V8_INLINE static bool HasHeapObjectTag(const internal::Address value) {
451    return (value & kHeapObjectTagMask) == static_cast<Address>(kHeapObjectTag);
452  }
453
454  V8_INLINE static int SmiValue(const internal::Address value) {
455    return PlatformSmiTagging::SmiToInt(value);
456  }
457
458  V8_INLINE static constexpr internal::Address IntToSmi(int value) {
459    return internal::IntToSmi(value);
460  }
461
462  V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
463    return PlatformSmiTagging::IsValidSmi(value);
464  }
465
466  V8_INLINE static int GetInstanceType(const internal::Address obj) {
467    typedef internal::Address A;
468    A map = ReadTaggedPointerField(obj, kHeapObjectMapOffset);
469#ifdef V8_MAP_PACKING
470    map = UnpackMapWord(map);
471#endif
472    return ReadRawField<uint16_t>(map, kMapInstanceTypeOffset);
473  }
474
475  V8_INLINE static int GetOddballKind(const internal::Address obj) {
476    return SmiValue(ReadTaggedSignedField(obj, kOddballKindOffset));
477  }
478
479  V8_INLINE static bool IsExternalTwoByteString(int instance_type) {
480    int representation = (instance_type & kStringRepresentationAndEncodingMask);
481    return representation == kExternalTwoByteRepresentationTag;
482  }
483
484  V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) {
485    uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
486    return *addr & static_cast<uint8_t>(1U << shift);
487  }
488
489  V8_INLINE static void UpdateNodeFlag(internal::Address* obj, bool value,
490                                       int shift) {
491    uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
492    uint8_t mask = static_cast<uint8_t>(1U << shift);
493    *addr = static_cast<uint8_t>((*addr & ~mask) | (value << shift));
494  }
495
496  V8_INLINE static uint8_t GetNodeState(internal::Address* obj) {
497    uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
498    return *addr & kNodeStateMask;
499  }
500
501  V8_INLINE static void UpdateNodeState(internal::Address* obj, uint8_t value) {
502    uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
503    *addr = static_cast<uint8_t>((*addr & ~kNodeStateMask) | value);
504  }
505
506  V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, uint32_t slot,
507                                        void* data) {
508    internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
509                             kIsolateEmbedderDataOffset +
510                             slot * kApiSystemPointerSize;
511    *reinterpret_cast<void**>(addr) = data;
512  }
513
514  V8_INLINE static void* GetEmbedderData(const v8::Isolate* isolate,
515                                         uint32_t slot) {
516    internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
517                             kIsolateEmbedderDataOffset +
518                             slot * kApiSystemPointerSize;
519    return *reinterpret_cast<void* const*>(addr);
520  }
521
522  V8_INLINE static void IncrementLongTasksStatsCounter(v8::Isolate* isolate) {
523    internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
524                             kIsolateLongTaskStatsCounterOffset;
525    ++(*reinterpret_cast<size_t*>(addr));
526  }
527
528  V8_INLINE static internal::Address* GetRoot(v8::Isolate* isolate, int index) {
529    internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
530                             kIsolateRootsOffset +
531                             index * kApiSystemPointerSize;
532    return reinterpret_cast<internal::Address*>(addr);
533  }
534
535  template <typename T>
536  V8_INLINE static T ReadRawField(internal::Address heap_object_ptr,
537                                  int offset) {
538    internal::Address addr = heap_object_ptr + offset - kHeapObjectTag;
539#ifdef V8_COMPRESS_POINTERS
540    if (sizeof(T) > kApiTaggedSize) {
541      // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
542      // fields (external pointers, doubles and BigInt data) are only
543      // kTaggedSize aligned so we have to use unaligned pointer friendly way of
544      // accessing them in order to avoid undefined behavior in C++ code.
545      T r;
546      memcpy(&r, reinterpret_cast<void*>(addr), sizeof(T));
547      return r;
548    }
549#endif
550    return *reinterpret_cast<const T*>(addr);
551  }
552
553  V8_INLINE static internal::Address ReadTaggedPointerField(
554      internal::Address heap_object_ptr, int offset) {
555#ifdef V8_COMPRESS_POINTERS
556    uint32_t value = ReadRawField<uint32_t>(heap_object_ptr, offset);
557    internal::Address base =
558        GetPtrComprCageBaseFromOnHeapAddress(heap_object_ptr);
559    return base + static_cast<internal::Address>(static_cast<uintptr_t>(value));
560#else
561    return ReadRawField<internal::Address>(heap_object_ptr, offset);
562#endif
563  }
564
565  V8_INLINE static internal::Address ReadTaggedSignedField(
566      internal::Address heap_object_ptr, int offset) {
567#ifdef V8_COMPRESS_POINTERS
568    uint32_t value = ReadRawField<uint32_t>(heap_object_ptr, offset);
569    return static_cast<internal::Address>(static_cast<uintptr_t>(value));
570#else
571    return ReadRawField<internal::Address>(heap_object_ptr, offset);
572#endif
573  }
574
575  V8_INLINE static internal::Isolate* GetIsolateForSandbox(
576      internal::Address obj) {
577#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
578    return internal::IsolateFromNeverReadOnlySpaceObject(obj);
579#else
580    // Not used in non-sandbox mode.
581    return nullptr;
582#endif
583  }
584
585  V8_INLINE static Address DecodeExternalPointer(
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
595  V8_INLINE static internal::Address ReadExternalPointerField(
596      internal::Isolate* isolate, internal::Address heap_object_ptr, int offset,
597      ExternalPointerTag tag) {
598#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
599    internal::ExternalPointer_t encoded_value =
600        ReadRawField<uint32_t>(heap_object_ptr, offset);
601    // We currently have to treat zero as nullptr in embedder slots.
602    return encoded_value ? DecodeExternalPointer(isolate, encoded_value, tag)
603                         : 0;
604#else
605    return ReadRawField<Address>(heap_object_ptr, offset);
606#endif
607  }
608
609#ifdef V8_COMPRESS_POINTERS
610  V8_INLINE static internal::Address GetPtrComprCageBaseFromOnHeapAddress(
611      internal::Address addr) {
612    return addr & -static_cast<intptr_t>(kPtrComprCageBaseAlignment);
613  }
614
615  V8_INLINE static internal::Address DecompressTaggedAnyField(
616      internal::Address heap_object_ptr, uint32_t value) {
617    internal::Address base =
618        GetPtrComprCageBaseFromOnHeapAddress(heap_object_ptr);
619    return base + static_cast<internal::Address>(static_cast<uintptr_t>(value));
620  }
621
622#endif  // V8_COMPRESS_POINTERS
623};
624
625// Only perform cast check for types derived from v8::Data since
626// other types do not implement the Cast method.
627template <bool PerformCheck>
628struct CastCheck {
629  template <class T>
630  static void Perform(T* data);
631};
632
633template <>
634template <class T>
635void CastCheck<true>::Perform(T* data) {
636  T::Cast(data);
637}
638
639template <>
640template <class T>
641void CastCheck<false>::Perform(T* data) {}
642
643template <class T>
644V8_INLINE void PerformCastCheck(T* data) {
645  CastCheck<std::is_base_of<Data, T>::value &&
646            !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
647}
648
649// A base class for backing stores, which is needed due to vagaries of
650// how static casts work with std::shared_ptr.
651class BackingStoreBase {};
652
653// The maximum value in enum GarbageCollectionReason, defined in heap.h.
654// This is needed for histograms sampling garbage collection reasons.
655constexpr int kGarbageCollectionReasonMaxValue = 25;
656
657}  // namespace internal
658
659}  // namespace v8
660
661#endif  // INCLUDE_V8_INTERNAL_H_
662