• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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(
102     kApiSystemPointerSize == kApiInt64Size,
103     "Pointer compression can be enabled only for 64-bit architectures");
104 const int kApiTaggedSize = kApiInt32Size;
105 #else
106 const int kApiTaggedSize = kApiSystemPointerSize;
107 #endif
108 
109 constexpr bool PointerCompressionIsEnabled() {
110   return kApiTaggedSize != kApiSystemPointerSize;
111 }
112 
113 constexpr bool HeapSandboxIsEnabled() {
114 #ifdef V8_HEAP_SANDBOX
115   return true;
116 #else
117   return false;
118 #endif
119 }
120 
121 using ExternalPointer_t = Address;
122 
123 // If the heap sandbox is enabled, these tag values will be XORed with the
124 // external pointers in the external pointer table to prevent use of pointers of
125 // the wrong type.
126 enum ExternalPointerTag : Address {
127   kExternalPointerNullTag = static_cast<Address>(0ULL),
128   kArrayBufferBackingStoreTag = static_cast<Address>(1ULL << 48),
129   kTypedArrayExternalPointerTag = static_cast<Address>(2ULL << 48),
130   kDataViewDataPointerTag = static_cast<Address>(3ULL << 48),
131   kExternalStringResourceTag = static_cast<Address>(4ULL << 48),
132   kExternalStringResourceDataTag = static_cast<Address>(5ULL << 48),
133   kForeignForeignAddressTag = static_cast<Address>(6ULL << 48),
134   kNativeContextMicrotaskQueueTag = static_cast<Address>(7ULL << 48),
135   // TODO(v8:10391, saelo): Currently has to be zero so that raw zero values are
136   // also nullptr
137   kEmbedderDataSlotPayloadTag = static_cast<Address>(0ULL << 48),
138 };
139 
140 #ifdef V8_31BIT_SMIS_ON_64BIT_ARCH
141 using PlatformSmiTagging = SmiTagging<kApiInt32Size>;
142 #else
143 using PlatformSmiTagging = SmiTagging<kApiTaggedSize>;
144 #endif
145 
146 // TODO(ishell): Consinder adding kSmiShiftBits = kSmiShiftSize + kSmiTagSize
147 // since it's used much more often than the inividual constants.
148 const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize;
149 const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize;
150 const int kSmiMinValue = static_cast<int>(PlatformSmiTagging::kSmiMinValue);
151 const int kSmiMaxValue = static_cast<int>(PlatformSmiTagging::kSmiMaxValue);
152 constexpr bool SmiValuesAre31Bits() { return kSmiValueSize == 31; }
153 constexpr bool SmiValuesAre32Bits() { return kSmiValueSize == 32; }
154 
155 V8_INLINE static constexpr internal::Address IntToSmi(int value) {
156   return (static_cast<Address>(value) << (kSmiTagSize + kSmiShiftSize)) |
157          kSmiTag;
158 }
159 
160 // Converts encoded external pointer to address.
161 V8_EXPORT Address DecodeExternalPointerImpl(const Isolate* isolate,
162                                             ExternalPointer_t pointer,
163                                             ExternalPointerTag tag);
164 
165 // {obj} must be the raw tagged pointer representation of a HeapObject
166 // that's guaranteed to never be in ReadOnlySpace.
167 V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);
168 
169 // Returns if we need to throw when an error occurs. This infers the language
170 // mode based on the current context and the closure. This returns true if the
171 // language mode is strict.
172 V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate);
173 
174 /**
175  * This class exports constants and functionality from within v8 that
176  * is necessary to implement inline functions in the v8 api.  Don't
177  * depend on functions and constants defined here.
178  */
179 class Internals {
180  public:
181   // These values match non-compiler-dependent values defined within
182   // the implementation of v8.
183   static const int kHeapObjectMapOffset = 0;
184   static const int kMapInstanceTypeOffset = 1 * kApiTaggedSize + kApiInt32Size;
185   static const int kStringResourceOffset =
186       1 * kApiTaggedSize + 2 * kApiInt32Size;
187 
188   static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize;
189   static const int kJSObjectHeaderSize = 3 * kApiTaggedSize;
190   static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize;
191   static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize;
192   static const int kEmbedderDataSlotSize = kApiSystemPointerSize;
193 #ifdef V8_HEAP_SANDBOX
194   static const int kEmbedderDataSlotRawPayloadOffset = kApiTaggedSize;
195 #endif
196   static const int kNativeContextEmbedderDataOffset = 6 * kApiTaggedSize;
197   static const int kFullStringRepresentationMask = 0x0f;
198   static const int kStringEncodingMask = 0x8;
199   static const int kExternalTwoByteRepresentationTag = 0x02;
200   static const int kExternalOneByteRepresentationTag = 0x0a;
201 
202   static const uint32_t kNumIsolateDataSlots = 4;
203 
204   // IsolateData layout guarantees.
205   static const int kIsolateEmbedderDataOffset = 0;
206   static const int kIsolateFastCCallCallerFpOffset =
207       kNumIsolateDataSlots * kApiSystemPointerSize;
208   static const int kIsolateFastCCallCallerPcOffset =
209       kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize;
210   static const int kIsolateStackGuardOffset =
211       kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize;
212   static const int kIsolateRootsOffset =
213       kIsolateStackGuardOffset + 7 * kApiSystemPointerSize;
214 
215   static const int kExternalPointerTableBufferOffset = 0;
216   static const int kExternalPointerTableLengthOffset =
217       kExternalPointerTableBufferOffset + kApiSystemPointerSize;
218   static const int kExternalPointerTableCapacityOffset =
219       kExternalPointerTableLengthOffset + kApiInt32Size;
220 
221   static const int kUndefinedValueRootIndex = 4;
222   static const int kTheHoleValueRootIndex = 5;
223   static const int kNullValueRootIndex = 6;
224   static const int kTrueValueRootIndex = 7;
225   static const int kFalseValueRootIndex = 8;
226   static const int kEmptyStringRootIndex = 9;
227 
228   static const int kNodeClassIdOffset = 1 * kApiSystemPointerSize;
229   static const int kNodeFlagsOffset = 1 * kApiSystemPointerSize + 3;
230   static const int kNodeStateMask = 0x7;
231   static const int kNodeStateIsWeakValue = 2;
232   static const int kNodeStateIsPendingValue = 3;
233 
234   static const int kFirstNonstringType = 0x40;
235   static const int kOddballType = 0x43;
236   static const int kForeignType = 0x46;
237   static const int kJSSpecialApiObjectType = 0x410;
238   static const int kJSApiObjectType = 0x420;
239   static const int kJSObjectType = 0x421;
240 
241   static const int kUndefinedOddballKind = 5;
242   static const int kNullOddballKind = 3;
243 
244   // Constants used by PropertyCallbackInfo to check if we should throw when an
245   // error occurs.
246   static const int kThrowOnError = 0;
247   static const int kDontThrow = 1;
248   static const int kInferShouldThrowMode = 2;
249 
250   // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an
251   // incremental GC once the external memory reaches this limit.
252   static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024;
253 
254   V8_EXPORT static void CheckInitializedImpl(v8::Isolate* isolate);
255   V8_INLINE static void CheckInitialized(v8::Isolate* isolate) {
256 #ifdef V8_ENABLE_CHECKS
257     CheckInitializedImpl(isolate);
258 #endif
259   }
260 
261   V8_INLINE static bool HasHeapObjectTag(const internal::Address value) {
262     return (value & kHeapObjectTagMask) == static_cast<Address>(kHeapObjectTag);
263   }
264 
265   V8_INLINE static int SmiValue(const internal::Address value) {
266     return PlatformSmiTagging::SmiToInt(value);
267   }
268 
269   V8_INLINE static constexpr internal::Address IntToSmi(int value) {
270     return internal::IntToSmi(value);
271   }
272 
273   V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
274     return PlatformSmiTagging::IsValidSmi(value);
275   }
276 
277   V8_INLINE static int GetInstanceType(const internal::Address obj) {
278     typedef internal::Address A;
279     A map = ReadTaggedPointerField(obj, kHeapObjectMapOffset);
280     return ReadRawField<uint16_t>(map, kMapInstanceTypeOffset);
281   }
282 
283   V8_INLINE static int GetOddballKind(const internal::Address obj) {
284     return SmiValue(ReadTaggedSignedField(obj, kOddballKindOffset));
285   }
286 
287   V8_INLINE static bool IsExternalTwoByteString(int instance_type) {
288     int representation = (instance_type & kFullStringRepresentationMask);
289     return representation == kExternalTwoByteRepresentationTag;
290   }
291 
292   V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) {
293     uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
294     return *addr & static_cast<uint8_t>(1U << shift);
295   }
296 
297   V8_INLINE static void UpdateNodeFlag(internal::Address* obj, bool value,
298                                        int shift) {
299     uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
300     uint8_t mask = static_cast<uint8_t>(1U << shift);
301     *addr = static_cast<uint8_t>((*addr & ~mask) | (value << shift));
302   }
303 
304   V8_INLINE static uint8_t GetNodeState(internal::Address* obj) {
305     uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
306     return *addr & kNodeStateMask;
307   }
308 
309   V8_INLINE static void UpdateNodeState(internal::Address* obj, uint8_t value) {
310     uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
311     *addr = static_cast<uint8_t>((*addr & ~kNodeStateMask) | value);
312   }
313 
314   V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, uint32_t slot,
315                                         void* data) {
316     internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
317                              kIsolateEmbedderDataOffset +
318                              slot * kApiSystemPointerSize;
319     *reinterpret_cast<void**>(addr) = data;
320   }
321 
322   V8_INLINE static void* GetEmbedderData(const v8::Isolate* isolate,
323                                          uint32_t slot) {
324     internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
325                              kIsolateEmbedderDataOffset +
326                              slot * kApiSystemPointerSize;
327     return *reinterpret_cast<void* const*>(addr);
328   }
329 
330   V8_INLINE static internal::Address* GetRoot(v8::Isolate* isolate, int index) {
331     internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
332                              kIsolateRootsOffset +
333                              index * kApiSystemPointerSize;
334     return reinterpret_cast<internal::Address*>(addr);
335   }
336 
337   template <typename T>
338   V8_INLINE static T ReadRawField(internal::Address heap_object_ptr,
339                                   int offset) {
340     internal::Address addr = heap_object_ptr + offset - kHeapObjectTag;
341 #ifdef V8_COMPRESS_POINTERS
342     if (sizeof(T) > kApiTaggedSize) {
343       // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
344       // fields (external pointers, doubles and BigInt data) are only
345       // kTaggedSize aligned so we have to use unaligned pointer friendly way of
346       // accessing them in order to avoid undefined behavior in C++ code.
347       T r;
348       memcpy(&r, reinterpret_cast<void*>(addr), sizeof(T));
349       return r;
350     }
351 #endif
352     return *reinterpret_cast<const T*>(addr);
353   }
354 
355   V8_INLINE static internal::Address ReadTaggedPointerField(
356       internal::Address heap_object_ptr, int offset) {
357 #ifdef V8_COMPRESS_POINTERS
358     uint32_t value = ReadRawField<uint32_t>(heap_object_ptr, offset);
359     internal::Address root = GetRootFromOnHeapAddress(heap_object_ptr);
360     return root + static_cast<internal::Address>(static_cast<uintptr_t>(value));
361 #else
362     return ReadRawField<internal::Address>(heap_object_ptr, offset);
363 #endif
364   }
365 
366   V8_INLINE static internal::Address ReadTaggedSignedField(
367       internal::Address heap_object_ptr, int offset) {
368 #ifdef V8_COMPRESS_POINTERS
369     uint32_t value = ReadRawField<uint32_t>(heap_object_ptr, offset);
370     return static_cast<internal::Address>(static_cast<uintptr_t>(value));
371 #else
372     return ReadRawField<internal::Address>(heap_object_ptr, offset);
373 #endif
374   }
375 
376   V8_INLINE static internal::Isolate* GetIsolateForHeapSandbox(
377       internal::Address obj) {
378 #ifdef V8_HEAP_SANDBOX
379     return internal::IsolateFromNeverReadOnlySpaceObject(obj);
380 #else
381     // Not used in non-sandbox mode.
382     return nullptr;
383 #endif
384   }
385 
386   V8_INLINE static Address DecodeExternalPointer(
387       const Isolate* isolate, ExternalPointer_t encoded_pointer,
388       ExternalPointerTag tag) {
389 #ifdef V8_HEAP_SANDBOX
390     return internal::DecodeExternalPointerImpl(isolate, encoded_pointer, tag);
391 #else
392     return encoded_pointer;
393 #endif
394   }
395 
396   V8_INLINE static internal::Address ReadExternalPointerField(
397       internal::Isolate* isolate, internal::Address heap_object_ptr, int offset,
398       ExternalPointerTag tag) {
399 #ifdef V8_HEAP_SANDBOX
400     internal::ExternalPointer_t encoded_value =
401         ReadRawField<uint32_t>(heap_object_ptr, offset);
402     // We currently have to treat zero as nullptr in embedder slots.
403     return encoded_value ? DecodeExternalPointer(isolate, encoded_value, tag)
404                          : 0;
405 #else
406     return ReadRawField<Address>(heap_object_ptr, offset);
407 #endif
408   }
409 
410 #ifdef V8_COMPRESS_POINTERS
411   // See v8:7703 or src/ptr-compr.* for details about pointer compression.
412   static constexpr size_t kPtrComprHeapReservationSize = size_t{1} << 32;
413   static constexpr size_t kPtrComprIsolateRootAlignment = size_t{1} << 32;
414 
415   V8_INLINE static internal::Address GetRootFromOnHeapAddress(
416       internal::Address addr) {
417     return addr & -static_cast<intptr_t>(kPtrComprIsolateRootAlignment);
418   }
419 
420   V8_INLINE static internal::Address DecompressTaggedAnyField(
421       internal::Address heap_object_ptr, uint32_t value) {
422     internal::Address root = GetRootFromOnHeapAddress(heap_object_ptr);
423     return root + static_cast<internal::Address>(static_cast<uintptr_t>(value));
424   }
425 
426 #endif  // V8_COMPRESS_POINTERS
427 };
428 
429 // Only perform cast check for types derived from v8::Data since
430 // other types do not implement the Cast method.
431 template <bool PerformCheck>
432 struct CastCheck {
433   template <class T>
434   static void Perform(T* data);
435 };
436 
437 template <>
438 template <class T>
439 void CastCheck<true>::Perform(T* data) {
440   T::Cast(data);
441 }
442 
443 template <>
444 template <class T>
445 void CastCheck<false>::Perform(T* data) {}
446 
447 template <class T>
448 V8_INLINE void PerformCastCheck(T* data) {
449   CastCheck<std::is_base_of<Data, T>::value &&
450             !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
451 }
452 
453 // A base class for backing stores, which is needed due to vagaries of
454 // how static casts work with std::shared_ptr.
455 class BackingStoreBase {};
456 
457 }  // namespace internal
458 }  // namespace v8
459 
460 #endif  // INCLUDE_V8_INTERNAL_H_
461