123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- // Copyright 2018 the V8 project authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
-
- #ifndef INCLUDE_V8_INTERNAL_H_
- #define INCLUDE_V8_INTERNAL_H_
-
- #include <stddef.h>
- #include <stdint.h>
- #include <string.h>
- #include <type_traits>
-
- #include "v8-version.h" // NOLINT(build/include)
- #include "v8config.h" // NOLINT(build/include)
-
- namespace v8 {
-
- class Context;
- class Data;
- class Isolate;
-
- namespace internal {
-
- class Isolate;
-
- typedef uintptr_t Address;
- static const Address kNullAddress = 0;
-
- /**
- * Configuration of tagging scheme.
- */
- const int kApiSystemPointerSize = sizeof(void*);
- const int kApiDoubleSize = sizeof(double);
- const int kApiInt32Size = sizeof(int32_t);
- const int kApiInt64Size = sizeof(int64_t);
-
- // Tag information for HeapObject.
- const int kHeapObjectTag = 1;
- const int kWeakHeapObjectTag = 3;
- const int kHeapObjectTagSize = 2;
- const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1;
-
- // Tag information for Smi.
- const int kSmiTag = 0;
- const int kSmiTagSize = 1;
- const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1;
-
- template <size_t tagged_ptr_size>
- struct SmiTagging;
-
- constexpr intptr_t kIntptrAllBitsSet = intptr_t{-1};
- constexpr uintptr_t kUintptrAllBitsSet =
- static_cast<uintptr_t>(kIntptrAllBitsSet);
-
- // Smi constants for systems where tagged pointer is a 32-bit value.
- template <>
- struct SmiTagging<4> {
- enum { kSmiShiftSize = 0, kSmiValueSize = 31 };
-
- static constexpr intptr_t kSmiMinValue =
- static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1));
- static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1);
-
- V8_INLINE static int SmiToInt(const internal::Address value) {
- int shift_bits = kSmiTagSize + kSmiShiftSize;
- // Shift down (requires >> to be sign extending).
- return static_cast<int>(static_cast<intptr_t>(value)) >> shift_bits;
- }
- V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
- // Is value in range [kSmiMinValue, kSmiMaxValue].
- // Use unsigned operations in order to avoid undefined behaviour in case of
- // signed integer overflow.
- return (static_cast<uintptr_t>(value) -
- static_cast<uintptr_t>(kSmiMinValue)) <=
- (static_cast<uintptr_t>(kSmiMaxValue) -
- static_cast<uintptr_t>(kSmiMinValue));
- }
- };
-
- // Smi constants for systems where tagged pointer is a 64-bit value.
- template <>
- struct SmiTagging<8> {
- enum { kSmiShiftSize = 31, kSmiValueSize = 32 };
-
- static constexpr intptr_t kSmiMinValue =
- static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1));
- static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1);
-
- V8_INLINE static int SmiToInt(const internal::Address value) {
- int shift_bits = kSmiTagSize + kSmiShiftSize;
- // Shift down and throw away top 32 bits.
- return static_cast<int>(static_cast<intptr_t>(value) >> shift_bits);
- }
- V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
- // To be representable as a long smi, the value must be a 32-bit integer.
- return (value == static_cast<int32_t>(value));
- }
- };
-
- #ifdef V8_COMPRESS_POINTERS
- static_assert(
- kApiSystemPointerSize == kApiInt64Size,
- "Pointer compression can be enabled only for 64-bit architectures");
- const int kApiTaggedSize = kApiInt32Size;
- #else
- const int kApiTaggedSize = kApiSystemPointerSize;
- #endif
-
- #ifdef V8_31BIT_SMIS_ON_64BIT_ARCH
- using PlatformSmiTagging = SmiTagging<kApiInt32Size>;
- #else
- using PlatformSmiTagging = SmiTagging<kApiTaggedSize>;
- #endif
-
- const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize;
- const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize;
- const int kSmiMinValue = static_cast<int>(PlatformSmiTagging::kSmiMinValue);
- const int kSmiMaxValue = static_cast<int>(PlatformSmiTagging::kSmiMaxValue);
- constexpr bool SmiValuesAre31Bits() { return kSmiValueSize == 31; }
- constexpr bool SmiValuesAre32Bits() { return kSmiValueSize == 32; }
-
- V8_INLINE static constexpr internal::Address IntToSmi(int value) {
- return (static_cast<Address>(value) << (kSmiTagSize + kSmiShiftSize)) |
- kSmiTag;
- }
-
- /**
- * This class exports constants and functionality from within v8 that
- * is necessary to implement inline functions in the v8 api. Don't
- * depend on functions and constants defined here.
- */
- class Internals {
- public:
- // These values match non-compiler-dependent values defined within
- // the implementation of v8.
- static const int kHeapObjectMapOffset = 0;
- static const int kMapInstanceTypeOffset = 1 * kApiTaggedSize + kApiInt32Size;
- static const int kStringResourceOffset =
- 1 * kApiTaggedSize + 2 * kApiInt32Size;
-
- static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize;
- static const int kForeignAddressOffset = kApiTaggedSize;
- static const int kJSObjectHeaderSize = 3 * kApiTaggedSize;
- static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize;
- static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize;
- static const int kEmbedderDataSlotSize = kApiSystemPointerSize;
- static const int kNativeContextEmbedderDataOffset = 7 * kApiTaggedSize;
- static const int kFullStringRepresentationMask = 0x0f;
- static const int kStringEncodingMask = 0x8;
- static const int kExternalTwoByteRepresentationTag = 0x02;
- static const int kExternalOneByteRepresentationTag = 0x0a;
-
- static const uint32_t kNumIsolateDataSlots = 4;
-
- static const int kIsolateEmbedderDataOffset = 0;
- static const int kExternalMemoryOffset =
- kNumIsolateDataSlots * kApiSystemPointerSize;
- static const int kExternalMemoryLimitOffset =
- kExternalMemoryOffset + kApiInt64Size;
- static const int kExternalMemoryAtLastMarkCompactOffset =
- kExternalMemoryLimitOffset + kApiInt64Size;
- static const int kIsolateRootsOffset =
- kExternalMemoryAtLastMarkCompactOffset + kApiInt64Size;
-
- static const int kUndefinedValueRootIndex = 4;
- static const int kTheHoleValueRootIndex = 5;
- static const int kNullValueRootIndex = 6;
- static const int kTrueValueRootIndex = 7;
- static const int kFalseValueRootIndex = 8;
- static const int kEmptyStringRootIndex = 9;
-
- static const int kNodeClassIdOffset = 1 * kApiSystemPointerSize;
- static const int kNodeFlagsOffset = 1 * kApiSystemPointerSize + 3;
- static const int kNodeStateMask = 0x7;
- static const int kNodeStateIsWeakValue = 2;
- static const int kNodeStateIsPendingValue = 3;
- static const int kNodeIsIndependentShift = 3;
- static const int kNodeIsActiveShift = 4;
-
- static const int kFirstNonstringType = 0x40;
- static const int kOddballType = 0x43;
- static const int kForeignType = 0x47;
- static const int kJSSpecialApiObjectType = 0x410;
- static const int kJSApiObjectType = 0x420;
- static const int kJSObjectType = 0x421;
-
- static const int kUndefinedOddballKind = 5;
- static const int kNullOddballKind = 3;
-
- // Constants used by PropertyCallbackInfo to check if we should throw when an
- // error occurs.
- static const int kThrowOnError = 0;
- static const int kDontThrow = 1;
- static const int kInferShouldThrowMode = 2;
-
- // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an
- // incremental GC once the external memory reaches this limit.
- static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024;
-
- V8_EXPORT static void CheckInitializedImpl(v8::Isolate* isolate);
- V8_INLINE static void CheckInitialized(v8::Isolate* isolate) {
- #ifdef V8_ENABLE_CHECKS
- CheckInitializedImpl(isolate);
- #endif
- }
-
- V8_INLINE static bool HasHeapObjectTag(const internal::Address value) {
- return (value & kHeapObjectTagMask) == static_cast<Address>(kHeapObjectTag);
- }
-
- V8_INLINE static int SmiValue(const internal::Address value) {
- return PlatformSmiTagging::SmiToInt(value);
- }
-
- V8_INLINE static constexpr internal::Address IntToSmi(int value) {
- return internal::IntToSmi(value);
- }
-
- V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
- return PlatformSmiTagging::IsValidSmi(value);
- }
-
- V8_INLINE static int GetInstanceType(const internal::Address obj) {
- typedef internal::Address A;
- A map = ReadTaggedPointerField(obj, kHeapObjectMapOffset);
- return ReadRawField<uint16_t>(map, kMapInstanceTypeOffset);
- }
-
- V8_INLINE static int GetOddballKind(const internal::Address obj) {
- return SmiValue(ReadTaggedSignedField(obj, kOddballKindOffset));
- }
-
- V8_INLINE static bool IsExternalTwoByteString(int instance_type) {
- int representation = (instance_type & kFullStringRepresentationMask);
- return representation == kExternalTwoByteRepresentationTag;
- }
-
- V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) {
- uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
- return *addr & static_cast<uint8_t>(1U << shift);
- }
-
- V8_INLINE static void UpdateNodeFlag(internal::Address* obj, bool value,
- int shift) {
- uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
- uint8_t mask = static_cast<uint8_t>(1U << shift);
- *addr = static_cast<uint8_t>((*addr & ~mask) | (value << shift));
- }
-
- V8_INLINE static uint8_t GetNodeState(internal::Address* obj) {
- uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
- return *addr & kNodeStateMask;
- }
-
- V8_INLINE static void UpdateNodeState(internal::Address* obj, uint8_t value) {
- uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
- *addr = static_cast<uint8_t>((*addr & ~kNodeStateMask) | value);
- }
-
- V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, uint32_t slot,
- void* data) {
- internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
- kIsolateEmbedderDataOffset +
- slot * kApiSystemPointerSize;
- *reinterpret_cast<void**>(addr) = data;
- }
-
- V8_INLINE static void* GetEmbedderData(const v8::Isolate* isolate,
- uint32_t slot) {
- internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
- kIsolateEmbedderDataOffset +
- slot * kApiSystemPointerSize;
- return *reinterpret_cast<void* const*>(addr);
- }
-
- V8_INLINE static internal::Address* GetRoot(v8::Isolate* isolate, int index) {
- internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
- kIsolateRootsOffset +
- index * kApiSystemPointerSize;
- return reinterpret_cast<internal::Address*>(addr);
- }
-
- template <typename T>
- V8_INLINE static T ReadRawField(internal::Address heap_object_ptr,
- int offset) {
- internal::Address addr = heap_object_ptr + offset - kHeapObjectTag;
- #ifdef V8_COMPRESS_POINTERS
- if (sizeof(T) > kApiTaggedSize) {
- // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
- // fields (external pointers, doubles and BigInt data) are only
- // kTaggedSize aligned so we have to use unaligned pointer friendly way of
- // accessing them in order to avoid undefined behavior in C++ code.
- T r;
- memcpy(&r, reinterpret_cast<void*>(addr), sizeof(T));
- return r;
- }
- #endif
- return *reinterpret_cast<const T*>(addr);
- }
-
- V8_INLINE static internal::Address ReadTaggedPointerField(
- internal::Address heap_object_ptr, int offset) {
- #ifdef V8_COMPRESS_POINTERS
- int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
- internal::Address root = GetRootFromOnHeapAddress(heap_object_ptr);
- return root + static_cast<internal::Address>(static_cast<intptr_t>(value));
- #else
- return ReadRawField<internal::Address>(heap_object_ptr, offset);
- #endif
- }
-
- V8_INLINE static internal::Address ReadTaggedSignedField(
- internal::Address heap_object_ptr, int offset) {
- #ifdef V8_COMPRESS_POINTERS
- int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
- return static_cast<internal::Address>(static_cast<intptr_t>(value));
- #else
- return ReadRawField<internal::Address>(heap_object_ptr, offset);
- #endif
- }
-
- #ifdef V8_COMPRESS_POINTERS
- // See v8:7703 or src/ptr-compr.* for details about pointer compression.
- static constexpr size_t kPtrComprHeapReservationSize = size_t{1} << 32;
- static constexpr size_t kPtrComprIsolateRootBias =
- kPtrComprHeapReservationSize / 2;
- static constexpr size_t kPtrComprIsolateRootAlignment = size_t{1} << 32;
-
- V8_INLINE static internal::Address GetRootFromOnHeapAddress(
- internal::Address addr) {
- return (addr + kPtrComprIsolateRootBias) &
- -static_cast<intptr_t>(kPtrComprIsolateRootAlignment);
- }
-
- V8_INLINE static internal::Address DecompressTaggedAnyField(
- internal::Address heap_object_ptr, int32_t value) {
- internal::Address root_mask = static_cast<internal::Address>(
- -static_cast<intptr_t>(value & kSmiTagMask));
- internal::Address root_or_zero =
- root_mask & GetRootFromOnHeapAddress(heap_object_ptr);
- return root_or_zero +
- static_cast<internal::Address>(static_cast<intptr_t>(value));
- }
- #endif // V8_COMPRESS_POINTERS
- };
-
- // Only perform cast check for types derived from v8::Data since
- // other types do not implement the Cast method.
- template <bool PerformCheck>
- struct CastCheck {
- template <class T>
- static void Perform(T* data);
- };
-
- template <>
- template <class T>
- void CastCheck<true>::Perform(T* data) {
- T::Cast(data);
- }
-
- template <>
- template <class T>
- void CastCheck<false>::Perform(T* data) {}
-
- template <class T>
- V8_INLINE void PerformCastCheck(T* data) {
- CastCheck<std::is_base_of<Data, T>::value>::Perform(data);
- }
-
- // {obj} must be the raw tagged pointer representation of a HeapObject
- // that's guaranteed to never be in ReadOnlySpace.
- V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);
-
- // Returns if we need to throw when an error occurs. This infers the language
- // mode based on the current context and the closure. This returns true if the
- // language mode is strict.
- V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate);
-
- } // namespace internal
- } // namespace v8
-
- #endif // INCLUDE_V8_INTERNAL_H_
|