Line data Source code
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 <type_traits>
11 :
12 : #include "v8-version.h" // NOLINT(build/include)
13 : #include "v8config.h" // NOLINT(build/include)
14 :
15 : namespace v8 {
16 :
17 : class Context;
18 : class Data;
19 : class Isolate;
20 :
21 : namespace internal {
22 :
23 : class Isolate;
24 :
25 : typedef uintptr_t Address;
26 : static const Address kNullAddress = 0;
27 :
28 : /**
29 : * Configuration of tagging scheme.
30 : */
31 : const int kApiSystemPointerSize = sizeof(void*);
32 : const int kApiTaggedSize = kApiSystemPointerSize;
33 : const int kApiDoubleSize = sizeof(double);
34 : const int kApiIntSize = sizeof(int);
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 : // Smi constants for systems where tagged pointer is a 32-bit value.
52 : template <>
53 : struct SmiTagging<4> {
54 : enum { kSmiShiftSize = 0, kSmiValueSize = 31 };
55 : V8_INLINE static int SmiToInt(const internal::Address value) {
56 : int shift_bits = kSmiTagSize + kSmiShiftSize;
57 : // Shift down (requires >> to be sign extending).
58 : return static_cast<int>(static_cast<intptr_t>(value)) >> shift_bits;
59 : }
60 : V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
61 : // To be representable as an tagged small integer, the two
62 : // most-significant bits of 'value' must be either 00 or 11 due to
63 : // sign-extension. To check this we add 01 to the two
64 : // most-significant bits, and check if the most-significant bit is 0.
65 : //
66 : // CAUTION: The original code below:
67 : // bool result = ((value + 0x40000000) & 0x80000000) == 0;
68 : // may lead to incorrect results according to the C language spec, and
69 : // in fact doesn't work correctly with gcc4.1.1 in some cases: The
70 : // compiler may produce undefined results in case of signed integer
71 : // overflow. The computation must be done w/ unsigned ints.
72 : return static_cast<uintptr_t>(value) + 0x40000000U < 0x80000000U;
73 : }
74 : };
75 :
76 : // Smi constants for systems where tagged pointer is a 64-bit value.
77 : template <>
78 : struct SmiTagging<8> {
79 : enum { kSmiShiftSize = 31, kSmiValueSize = 32 };
80 : V8_INLINE static int SmiToInt(const internal::Address value) {
81 : int shift_bits = kSmiTagSize + kSmiShiftSize;
82 : // Shift down and throw away top 32 bits.
83 8070399941 : return static_cast<int>(static_cast<intptr_t>(value) >> shift_bits);
84 : }
85 : V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
86 : // To be representable as a long smi, the value must be a 32-bit integer.
87 3307 : return (value == static_cast<int32_t>(value));
88 : }
89 : };
90 :
91 : #if defined(V8_COMPRESS_POINTERS)
92 : static_assert(
93 : kApiSystemPointerSize == kApiInt64Size,
94 : "Pointer compression can be enabled only for 64-bit architectures");
95 : #endif
96 :
97 : #if defined(V8_COMPRESS_POINTERS) || defined(V8_31BIT_SMIS_ON_64BIT_ARCH)
98 : typedef SmiTagging<kApiIntSize> PlatformSmiTagging;
99 : #else
100 : typedef SmiTagging<kApiSystemPointerSize> PlatformSmiTagging;
101 : #endif
102 :
103 : const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize;
104 : const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize;
105 : const int kSmiMinValue = (static_cast<unsigned int>(-1)) << (kSmiValueSize - 1);
106 : const int kSmiMaxValue = -(kSmiMinValue + 1);
107 : constexpr bool SmiValuesAre31Bits() { return kSmiValueSize == 31; }
108 : constexpr bool SmiValuesAre32Bits() { return kSmiValueSize == 32; }
109 :
110 : V8_INLINE static constexpr internal::Address IntToSmi(int value) {
111 1498519192 : return (static_cast<Address>(value) << (kSmiTagSize + kSmiShiftSize)) |
112 1498519886 : kSmiTag;
113 : }
114 :
115 : /**
116 : * This class exports constants and functionality from within v8 that
117 : * is necessary to implement inline functions in the v8 api. Don't
118 : * depend on functions and constants defined here.
119 : */
120 : class Internals {
121 : public:
122 : // These values match non-compiler-dependent values defined within
123 : // the implementation of v8.
124 : static const int kHeapObjectMapOffset = 0;
125 : static const int kMapInstanceTypeOffset = 1 * kApiTaggedSize + kApiIntSize;
126 : static const int kStringResourceOffset = 1 * kApiTaggedSize + 2 * kApiIntSize;
127 :
128 : static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize;
129 : static const int kForeignAddressOffset = kApiTaggedSize;
130 : static const int kJSObjectHeaderSize = 3 * kApiTaggedSize;
131 : static const int kJSObjectHeaderSizeForEmbedderFields =
132 : (kJSObjectHeaderSize + kApiSystemPointerSize - 1) &
133 : -kApiSystemPointerSize;
134 : static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize;
135 : static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize;
136 : static const int kEmbedderDataSlotSize =
137 : #ifdef V8_COMPRESS_POINTERS
138 : 2 *
139 : #endif
140 : kApiSystemPointerSize;
141 : static const int kNativeContextEmbedderDataOffset = 7 * kApiTaggedSize;
142 : static const int kFullStringRepresentationMask = 0x0f;
143 : static const int kStringEncodingMask = 0x8;
144 : static const int kExternalTwoByteRepresentationTag = 0x02;
145 : static const int kExternalOneByteRepresentationTag = 0x0a;
146 :
147 : static const uint32_t kNumIsolateDataSlots = 4;
148 :
149 : static const int kIsolateEmbedderDataOffset = 0;
150 : static const int kExternalMemoryOffset =
151 : kNumIsolateDataSlots * kApiTaggedSize;
152 : static const int kExternalMemoryLimitOffset =
153 : kExternalMemoryOffset + kApiInt64Size;
154 : static const int kExternalMemoryAtLastMarkCompactOffset =
155 : kExternalMemoryLimitOffset + kApiInt64Size;
156 : static const int kIsolateRootsOffset =
157 : kExternalMemoryAtLastMarkCompactOffset + kApiInt64Size;
158 :
159 : static const int kUndefinedValueRootIndex = 4;
160 : static const int kTheHoleValueRootIndex = 5;
161 : static const int kNullValueRootIndex = 6;
162 : static const int kTrueValueRootIndex = 7;
163 : static const int kFalseValueRootIndex = 8;
164 : static const int kEmptyStringRootIndex = 9;
165 :
166 : static const int kNodeClassIdOffset = 1 * kApiTaggedSize;
167 : static const int kNodeFlagsOffset = 1 * kApiTaggedSize + 3;
168 : static const int kNodeStateMask = 0x7;
169 : static const int kNodeStateIsWeakValue = 2;
170 : static const int kNodeStateIsPendingValue = 3;
171 : static const int kNodeStateIsNearDeathValue = 4;
172 : static const int kNodeIsIndependentShift = 3;
173 : static const int kNodeIsActiveShift = 4;
174 :
175 : static const int kFirstNonstringType = 0x80;
176 : static const int kOddballType = 0x83;
177 : static const int kForeignType = 0x87;
178 : static const int kJSSpecialApiObjectType = 0x410;
179 : static const int kJSApiObjectType = 0x420;
180 : static const int kJSObjectType = 0x421;
181 :
182 : static const int kUndefinedOddballKind = 5;
183 : static const int kNullOddballKind = 3;
184 :
185 : // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an
186 : // incremental GC once the external memory reaches this limit.
187 : static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024;
188 :
189 : V8_EXPORT static void CheckInitializedImpl(v8::Isolate* isolate);
190 : V8_INLINE static void CheckInitialized(v8::Isolate* isolate) {
191 : #ifdef V8_ENABLE_CHECKS
192 : CheckInitializedImpl(isolate);
193 : #endif
194 : }
195 :
196 : V8_INLINE static bool HasHeapObjectTag(const internal::Address value) {
197 230973419 : return (value & kHeapObjectTagMask) == static_cast<Address>(kHeapObjectTag);
198 : }
199 :
200 : V8_INLINE static int SmiValue(const internal::Address value) {
201 : return PlatformSmiTagging::SmiToInt(value);
202 : }
203 :
204 : V8_INLINE static constexpr internal::Address IntToSmi(int value) {
205 : return internal::IntToSmi(value);
206 : }
207 :
208 : V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
209 : return PlatformSmiTagging::IsValidSmi(value);
210 : }
211 :
212 : V8_INLINE static int GetInstanceType(const internal::Address obj) {
213 : typedef internal::Address A;
214 : A map = ReadTaggedPointerField(obj, kHeapObjectMapOffset);
215 8815106 : return ReadRawField<uint16_t>(map, kMapInstanceTypeOffset);
216 : }
217 :
218 : V8_INLINE static int GetOddballKind(const internal::Address obj) {
219 : return SmiValue(ReadTaggedSignedField(obj, kOddballKindOffset));
220 : }
221 :
222 : V8_INLINE static bool IsExternalTwoByteString(int instance_type) {
223 31 : int representation = (instance_type & kFullStringRepresentationMask);
224 : return representation == kExternalTwoByteRepresentationTag;
225 : }
226 :
227 : V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) {
228 : uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
229 46 : return *addr & static_cast<uint8_t>(1U << shift);
230 : }
231 :
232 : V8_INLINE static void UpdateNodeFlag(internal::Address* obj, bool value,
233 : int shift) {
234 : uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
235 : uint8_t mask = static_cast<uint8_t>(1U << shift);
236 104874 : *addr = static_cast<uint8_t>((*addr & ~mask) | (value << shift));
237 : }
238 :
239 : V8_INLINE static uint8_t GetNodeState(internal::Address* obj) {
240 : uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
241 20 : return *addr & kNodeStateMask;
242 : }
243 :
244 : V8_INLINE static void UpdateNodeState(internal::Address* obj, uint8_t value) {
245 : uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
246 : *addr = static_cast<uint8_t>((*addr & ~kNodeStateMask) | value);
247 : }
248 :
249 : V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, uint32_t slot,
250 : void* data) {
251 50 : internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
252 40 : kIsolateEmbedderDataOffset +
253 90 : slot * kApiSystemPointerSize;
254 58961 : *reinterpret_cast<void**>(addr) = data;
255 : }
256 :
257 : V8_INLINE static void* GetEmbedderData(const v8::Isolate* isolate,
258 : uint32_t slot) {
259 100 : internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
260 60 : kIsolateEmbedderDataOffset +
261 160 : slot * kApiSystemPointerSize;
262 345028 : return *reinterpret_cast<void* const*>(addr);
263 : }
264 :
265 : V8_INLINE static internal::Address* GetRoot(v8::Isolate* isolate, int index) {
266 : internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
267 2291681 : kIsolateRootsOffset +
268 6973407 : index * kApiSystemPointerSize;
269 6048283 : return reinterpret_cast<internal::Address*>(addr);
270 : }
271 :
272 : template <typename T>
273 : V8_INLINE static T ReadRawField(internal::Address heap_object_ptr,
274 : int offset) {
275 58854791 : internal::Address addr = heap_object_ptr + offset - kHeapObjectTag;
276 58854791 : return *reinterpret_cast<const T*>(addr);
277 : }
278 :
279 : V8_INLINE static internal::Address ReadTaggedPointerField(
280 : internal::Address heap_object_ptr, int offset) {
281 : #ifdef V8_COMPRESS_POINTERS
282 : int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
283 : internal::Address root = GetRootFromOnHeapAddress(heap_object_ptr);
284 : return root + static_cast<internal::Address>(static_cast<intptr_t>(value));
285 : #else
286 : return ReadRawField<internal::Address>(heap_object_ptr, offset);
287 : #endif
288 : }
289 :
290 : V8_INLINE static internal::Address ReadTaggedSignedField(
291 : internal::Address heap_object_ptr, int offset) {
292 : #ifdef V8_COMPRESS_POINTERS
293 : int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
294 : return static_cast<internal::Address>(static_cast<intptr_t>(value));
295 : #else
296 : return ReadRawField<internal::Address>(heap_object_ptr, offset);
297 : #endif
298 : }
299 :
300 : V8_INLINE static internal::Address ReadTaggedAnyField(
301 : internal::Address heap_object_ptr, int offset) {
302 : #ifdef V8_COMPRESS_POINTERS
303 : int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
304 : internal::Address root_mask = static_cast<internal::Address>(
305 : -static_cast<intptr_t>(value & kSmiTagMask));
306 : internal::Address root_or_zero =
307 : root_mask & GetRootFromOnHeapAddress(heap_object_ptr);
308 : return root_or_zero +
309 : static_cast<internal::Address>(static_cast<intptr_t>(value));
310 : #else
311 : return ReadRawField<internal::Address>(heap_object_ptr, offset);
312 : #endif
313 : }
314 :
315 : #ifdef V8_COMPRESS_POINTERS
316 : static constexpr size_t kPtrComprHeapReservationSize = size_t{1} << 32;
317 : static constexpr size_t kPtrComprIsolateRootBias =
318 : kPtrComprHeapReservationSize / 2;
319 : static constexpr size_t kPtrComprIsolateRootAlignment = size_t{1} << 32;
320 :
321 : V8_INLINE static internal::Address GetRootFromOnHeapAddress(
322 : internal::Address addr) {
323 : return (addr + kPtrComprIsolateRootBias) &
324 : -static_cast<intptr_t>(kPtrComprIsolateRootAlignment);
325 : }
326 :
327 : #else
328 :
329 : template <typename T>
330 : V8_INLINE static T ReadEmbedderData(const v8::Context* context, int index) {
331 : typedef internal::Address A;
332 : typedef internal::Internals I;
333 182393 : A ctx = *reinterpret_cast<const A*>(context);
334 : A embedder_data =
335 : I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset);
336 : int value_offset =
337 654 : I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index);
338 : return I::ReadRawField<T>(embedder_data, value_offset);
339 : }
340 : #endif // V8_COMPRESS_POINTERS
341 : };
342 :
343 : // Only perform cast check for types derived from v8::Data since
344 : // other types do not implement the Cast method.
345 : template <bool PerformCheck>
346 : struct CastCheck {
347 : template <class T>
348 : static void Perform(T* data);
349 : };
350 :
351 : template <>
352 : template <class T>
353 75 : void CastCheck<true>::Perform(T* data) {
354 : T::Cast(data);
355 75 : }
356 :
357 : template <>
358 : template <class T>
359 5 : void CastCheck<false>::Perform(T* data) {}
360 :
361 : template <class T>
362 : V8_INLINE void PerformCastCheck(T* data) {
363 80 : CastCheck<std::is_base_of<Data, T>::value>::Perform(data);
364 : }
365 :
366 : // {obj} must be the raw tagged pointer representation of a HeapObject
367 : // that's guaranteed to never be in ReadOnlySpace.
368 : V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);
369 :
370 : } // namespace internal
371 : } // namespace v8
372 :
373 : #endif // INCLUDE_V8_INTERNAL_H_
|