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