v8-internal.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  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. #ifndef INCLUDE_V8_INTERNAL_H_
  5. #define INCLUDE_V8_INTERNAL_H_
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <string.h>
  9. #include <type_traits>
  10. #include "v8-version.h" // NOLINT(build/include)
  11. #include "v8config.h" // NOLINT(build/include)
  12. namespace v8 {
  13. class Context;
  14. class Data;
  15. class Isolate;
  16. namespace internal {
  17. class Isolate;
  18. typedef uintptr_t Address;
  19. static const Address kNullAddress = 0;
  20. /**
  21. * Configuration of tagging scheme.
  22. */
  23. const int kApiSystemPointerSize = sizeof(void*);
  24. const int kApiDoubleSize = sizeof(double);
  25. const int kApiInt32Size = sizeof(int32_t);
  26. const int kApiInt64Size = sizeof(int64_t);
  27. // Tag information for HeapObject.
  28. const int kHeapObjectTag = 1;
  29. const int kWeakHeapObjectTag = 3;
  30. const int kHeapObjectTagSize = 2;
  31. const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1;
  32. // Tag information for Smi.
  33. const int kSmiTag = 0;
  34. const int kSmiTagSize = 1;
  35. const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1;
  36. template <size_t tagged_ptr_size>
  37. struct SmiTagging;
  38. constexpr intptr_t kIntptrAllBitsSet = intptr_t{-1};
  39. constexpr uintptr_t kUintptrAllBitsSet =
  40. static_cast<uintptr_t>(kIntptrAllBitsSet);
  41. // Smi constants for systems where tagged pointer is a 32-bit value.
  42. template <>
  43. struct SmiTagging<4> {
  44. enum { kSmiShiftSize = 0, kSmiValueSize = 31 };
  45. static constexpr intptr_t kSmiMinValue =
  46. static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1));
  47. static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1);
  48. V8_INLINE static int SmiToInt(const internal::Address value) {
  49. int shift_bits = kSmiTagSize + kSmiShiftSize;
  50. // Truncate and shift down (requires >> to be sign extending).
  51. return static_cast<int32_t>(static_cast<uint32_t>(value)) >> shift_bits;
  52. }
  53. V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
  54. // Is value in range [kSmiMinValue, kSmiMaxValue].
  55. // Use unsigned operations in order to avoid undefined behaviour in case of
  56. // signed integer overflow.
  57. return (static_cast<uintptr_t>(value) -
  58. static_cast<uintptr_t>(kSmiMinValue)) <=
  59. (static_cast<uintptr_t>(kSmiMaxValue) -
  60. static_cast<uintptr_t>(kSmiMinValue));
  61. }
  62. };
  63. // Smi constants for systems where tagged pointer is a 64-bit value.
  64. template <>
  65. struct SmiTagging<8> {
  66. enum { kSmiShiftSize = 31, kSmiValueSize = 32 };
  67. static constexpr intptr_t kSmiMinValue =
  68. static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1));
  69. static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1);
  70. V8_INLINE static int SmiToInt(const internal::Address value) {
  71. int shift_bits = kSmiTagSize + kSmiShiftSize;
  72. // Shift down and throw away top 32 bits.
  73. return static_cast<int>(static_cast<intptr_t>(value) >> shift_bits);
  74. }
  75. V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
  76. // To be representable as a long smi, the value must be a 32-bit integer.
  77. return (value == static_cast<int32_t>(value));
  78. }
  79. };
  80. #ifdef V8_COMPRESS_POINTERS
  81. static_assert(
  82. kApiSystemPointerSize == kApiInt64Size,
  83. "Pointer compression can be enabled only for 64-bit architectures");
  84. const int kApiTaggedSize = kApiInt32Size;
  85. #else
  86. const int kApiTaggedSize = kApiSystemPointerSize;
  87. #endif
  88. #ifdef V8_31BIT_SMIS_ON_64BIT_ARCH
  89. using PlatformSmiTagging = SmiTagging<kApiInt32Size>;
  90. #else
  91. using PlatformSmiTagging = SmiTagging<kApiTaggedSize>;
  92. #endif
  93. // TODO(ishell): Consinder adding kSmiShiftBits = kSmiShiftSize + kSmiTagSize
  94. // since it's used much more often than the inividual constants.
  95. const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize;
  96. const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize;
  97. const int kSmiMinValue = static_cast<int>(PlatformSmiTagging::kSmiMinValue);
  98. const int kSmiMaxValue = static_cast<int>(PlatformSmiTagging::kSmiMaxValue);
  99. constexpr bool SmiValuesAre31Bits() { return kSmiValueSize == 31; }
  100. constexpr bool SmiValuesAre32Bits() { return kSmiValueSize == 32; }
  101. V8_INLINE static constexpr internal::Address IntToSmi(int value) {
  102. return (static_cast<Address>(value) << (kSmiTagSize + kSmiShiftSize)) |
  103. kSmiTag;
  104. }
  105. /**
  106. * This class exports constants and functionality from within v8 that
  107. * is necessary to implement inline functions in the v8 api. Don't
  108. * depend on functions and constants defined here.
  109. */
  110. class Internals {
  111. public:
  112. // These values match non-compiler-dependent values defined within
  113. // the implementation of v8.
  114. static const int kHeapObjectMapOffset = 0;
  115. static const int kMapInstanceTypeOffset = 1 * kApiTaggedSize + kApiInt32Size;
  116. static const int kStringResourceOffset =
  117. 1 * kApiTaggedSize + 2 * kApiInt32Size;
  118. static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize;
  119. static const int kForeignAddressOffset = kApiTaggedSize;
  120. static const int kJSObjectHeaderSize = 3 * kApiTaggedSize;
  121. static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize;
  122. static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize;
  123. static const int kEmbedderDataSlotSize = kApiSystemPointerSize;
  124. static const int kNativeContextEmbedderDataOffset = 6 * kApiTaggedSize;
  125. static const int kFullStringRepresentationMask = 0x0f;
  126. static const int kStringEncodingMask = 0x8;
  127. static const int kExternalTwoByteRepresentationTag = 0x02;
  128. static const int kExternalOneByteRepresentationTag = 0x0a;
  129. static const uint32_t kNumIsolateDataSlots = 4;
  130. // IsolateData layout guarantees.
  131. static const int kIsolateEmbedderDataOffset = 0;
  132. static const int kExternalMemoryOffset =
  133. kNumIsolateDataSlots * kApiSystemPointerSize;
  134. static const int kExternalMemoryLimitOffset =
  135. kExternalMemoryOffset + kApiInt64Size;
  136. static const int kExternalMemoryAtLastMarkCompactOffset =
  137. kExternalMemoryLimitOffset + kApiInt64Size;
  138. static const int kIsolateFastCCallCallerFpOffset =
  139. kExternalMemoryAtLastMarkCompactOffset + kApiInt64Size;
  140. static const int kIsolateFastCCallCallerPcOffset =
  141. kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize;
  142. static const int kIsolateStackGuardOffset =
  143. kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize;
  144. static const int kIsolateRootsOffset =
  145. kIsolateStackGuardOffset + 7 * kApiSystemPointerSize;
  146. static const int kUndefinedValueRootIndex = 4;
  147. static const int kTheHoleValueRootIndex = 5;
  148. static const int kNullValueRootIndex = 6;
  149. static const int kTrueValueRootIndex = 7;
  150. static const int kFalseValueRootIndex = 8;
  151. static const int kEmptyStringRootIndex = 9;
  152. static const int kNodeClassIdOffset = 1 * kApiSystemPointerSize;
  153. static const int kNodeFlagsOffset = 1 * kApiSystemPointerSize + 3;
  154. static const int kNodeStateMask = 0x7;
  155. static const int kNodeStateIsWeakValue = 2;
  156. static const int kNodeStateIsPendingValue = 3;
  157. static const int kFirstNonstringType = 0x40;
  158. static const int kOddballType = 0x43;
  159. static const int kForeignType = 0x46;
  160. static const int kJSSpecialApiObjectType = 0x410;
  161. static const int kJSApiObjectType = 0x420;
  162. static const int kJSObjectType = 0x421;
  163. static const int kUndefinedOddballKind = 5;
  164. static const int kNullOddballKind = 3;
  165. // Constants used by PropertyCallbackInfo to check if we should throw when an
  166. // error occurs.
  167. static const int kThrowOnError = 0;
  168. static const int kDontThrow = 1;
  169. static const int kInferShouldThrowMode = 2;
  170. // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an
  171. // incremental GC once the external memory reaches this limit.
  172. static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024;
  173. V8_EXPORT static void CheckInitializedImpl(v8::Isolate* isolate);
  174. V8_INLINE static void CheckInitialized(v8::Isolate* isolate) {
  175. #ifdef V8_ENABLE_CHECKS
  176. CheckInitializedImpl(isolate);
  177. #endif
  178. }
  179. V8_INLINE static bool HasHeapObjectTag(const internal::Address value) {
  180. return (value & kHeapObjectTagMask) == static_cast<Address>(kHeapObjectTag);
  181. }
  182. V8_INLINE static int SmiValue(const internal::Address value) {
  183. return PlatformSmiTagging::SmiToInt(value);
  184. }
  185. V8_INLINE static constexpr internal::Address IntToSmi(int value) {
  186. return internal::IntToSmi(value);
  187. }
  188. V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
  189. return PlatformSmiTagging::IsValidSmi(value);
  190. }
  191. V8_INLINE static int GetInstanceType(const internal::Address obj) {
  192. typedef internal::Address A;
  193. A map = ReadTaggedPointerField(obj, kHeapObjectMapOffset);
  194. return ReadRawField<uint16_t>(map, kMapInstanceTypeOffset);
  195. }
  196. V8_INLINE static int GetOddballKind(const internal::Address obj) {
  197. return SmiValue(ReadTaggedSignedField(obj, kOddballKindOffset));
  198. }
  199. V8_INLINE static bool IsExternalTwoByteString(int instance_type) {
  200. int representation = (instance_type & kFullStringRepresentationMask);
  201. return representation == kExternalTwoByteRepresentationTag;
  202. }
  203. V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) {
  204. uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
  205. return *addr & static_cast<uint8_t>(1U << shift);
  206. }
  207. V8_INLINE static void UpdateNodeFlag(internal::Address* obj, bool value,
  208. int shift) {
  209. uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
  210. uint8_t mask = static_cast<uint8_t>(1U << shift);
  211. *addr = static_cast<uint8_t>((*addr & ~mask) | (value << shift));
  212. }
  213. V8_INLINE static uint8_t GetNodeState(internal::Address* obj) {
  214. uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
  215. return *addr & kNodeStateMask;
  216. }
  217. V8_INLINE static void UpdateNodeState(internal::Address* obj, uint8_t value) {
  218. uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
  219. *addr = static_cast<uint8_t>((*addr & ~kNodeStateMask) | value);
  220. }
  221. V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, uint32_t slot,
  222. void* data) {
  223. internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
  224. kIsolateEmbedderDataOffset +
  225. slot * kApiSystemPointerSize;
  226. *reinterpret_cast<void**>(addr) = data;
  227. }
  228. V8_INLINE static void* GetEmbedderData(const v8::Isolate* isolate,
  229. uint32_t slot) {
  230. internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
  231. kIsolateEmbedderDataOffset +
  232. slot * kApiSystemPointerSize;
  233. return *reinterpret_cast<void* const*>(addr);
  234. }
  235. V8_INLINE static internal::Address* GetRoot(v8::Isolate* isolate, int index) {
  236. internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
  237. kIsolateRootsOffset +
  238. index * kApiSystemPointerSize;
  239. return reinterpret_cast<internal::Address*>(addr);
  240. }
  241. template <typename T>
  242. V8_INLINE static T ReadRawField(internal::Address heap_object_ptr,
  243. int offset) {
  244. internal::Address addr = heap_object_ptr + offset - kHeapObjectTag;
  245. #ifdef V8_COMPRESS_POINTERS
  246. if (sizeof(T) > kApiTaggedSize) {
  247. // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
  248. // fields (external pointers, doubles and BigInt data) are only
  249. // kTaggedSize aligned so we have to use unaligned pointer friendly way of
  250. // accessing them in order to avoid undefined behavior in C++ code.
  251. T r;
  252. memcpy(&r, reinterpret_cast<void*>(addr), sizeof(T));
  253. return r;
  254. }
  255. #endif
  256. return *reinterpret_cast<const T*>(addr);
  257. }
  258. V8_INLINE static internal::Address ReadTaggedPointerField(
  259. internal::Address heap_object_ptr, int offset) {
  260. #ifdef V8_COMPRESS_POINTERS
  261. int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
  262. internal::Address root = GetRootFromOnHeapAddress(heap_object_ptr);
  263. return root + static_cast<internal::Address>(static_cast<intptr_t>(value));
  264. #else
  265. return ReadRawField<internal::Address>(heap_object_ptr, offset);
  266. #endif
  267. }
  268. V8_INLINE static internal::Address ReadTaggedSignedField(
  269. internal::Address heap_object_ptr, int offset) {
  270. #ifdef V8_COMPRESS_POINTERS
  271. int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
  272. return static_cast<internal::Address>(static_cast<intptr_t>(value));
  273. #else
  274. return ReadRawField<internal::Address>(heap_object_ptr, offset);
  275. #endif
  276. }
  277. #ifdef V8_COMPRESS_POINTERS
  278. // See v8:7703 or src/ptr-compr.* for details about pointer compression.
  279. static constexpr size_t kPtrComprHeapReservationSize = size_t{1} << 32;
  280. static constexpr size_t kPtrComprIsolateRootAlignment = size_t{1} << 32;
  281. V8_INLINE static internal::Address GetRootFromOnHeapAddress(
  282. internal::Address addr) {
  283. return addr & -static_cast<intptr_t>(kPtrComprIsolateRootAlignment);
  284. }
  285. V8_INLINE static internal::Address DecompressTaggedAnyField(
  286. internal::Address heap_object_ptr, int32_t value) {
  287. internal::Address root_mask = static_cast<internal::Address>(
  288. -static_cast<intptr_t>(value & kSmiTagMask));
  289. internal::Address root_or_zero =
  290. root_mask & GetRootFromOnHeapAddress(heap_object_ptr);
  291. return root_or_zero +
  292. static_cast<internal::Address>(static_cast<intptr_t>(value));
  293. }
  294. #endif // V8_COMPRESS_POINTERS
  295. };
  296. // Only perform cast check for types derived from v8::Data since
  297. // other types do not implement the Cast method.
  298. template <bool PerformCheck>
  299. struct CastCheck {
  300. template <class T>
  301. static void Perform(T* data);
  302. };
  303. template <>
  304. template <class T>
  305. void CastCheck<true>::Perform(T* data) {
  306. T::Cast(data);
  307. }
  308. template <>
  309. template <class T>
  310. void CastCheck<false>::Perform(T* data) {}
  311. template <class T>
  312. V8_INLINE void PerformCastCheck(T* data) {
  313. CastCheck<std::is_base_of<Data, T>::value>::Perform(data);
  314. }
  315. // {obj} must be the raw tagged pointer representation of a HeapObject
  316. // that's guaranteed to never be in ReadOnlySpace.
  317. V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);
  318. // Returns if we need to throw when an error occurs. This infers the language
  319. // mode based on the current context and the closure. This returns true if the
  320. // language mode is strict.
  321. V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate);
  322. // A base class for backing stores, which is needed due to vagaries of
  323. // how static casts work with std::shared_ptr.
  324. class BackingStoreBase {};
  325. } // namespace internal
  326. } // namespace v8
  327. #endif // INCLUDE_V8_INTERNAL_H_