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 7860 : int shift_bits = kSmiTagSize + kSmiShiftSize;
82 : // Shift down and throw away top 32 bits.
83 8804416223 : 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 8467 : 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 0 : constexpr bool SmiValuesAre31Bits() { return kSmiValueSize == 31; }
108 367653 : constexpr bool SmiValuesAre32Bits() { return kSmiValueSize == 32; }
109 :
110 : V8_INLINE static constexpr internal::Address IntToSmi(int value) {
111 1605285276 : return (static_cast<Address>(value) << (kSmiTagSize + kSmiShiftSize)) |
112 1605285972 : 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 : // Constants used by PropertyCallbackInfo to check if we should throw when an
186 : // error occurs.
187 : static const int kThrowOnError = 0;
188 : static const int kDontThrow = 1;
189 : static const int kInferShouldThrowMode = 2;
190 :
191 : // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an
192 : // incremental GC once the external memory reaches this limit.
193 : static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024;
194 :
195 : V8_EXPORT static void CheckInitializedImpl(v8::Isolate* isolate);
196 : V8_INLINE static void CheckInitialized(v8::Isolate* isolate) {
197 : #ifdef V8_ENABLE_CHECKS
198 : CheckInitializedImpl(isolate);
199 : #endif
200 : }
201 :
202 : V8_INLINE static bool HasHeapObjectTag(const internal::Address value) {
203 224659503 : return (value & kHeapObjectTagMask) == static_cast<Address>(kHeapObjectTag);
204 : }
205 :
206 : V8_INLINE static int SmiValue(const internal::Address value) {
207 7860 : return PlatformSmiTagging::SmiToInt(value);
208 : }
209 :
210 : V8_INLINE static constexpr internal::Address IntToSmi(int value) {
211 117321 : return internal::IntToSmi(value);
212 : }
213 :
214 : V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
215 5905 : return PlatformSmiTagging::IsValidSmi(value);
216 : }
217 :
218 : V8_INLINE static int GetInstanceType(const internal::Address obj) {
219 : typedef internal::Address A;
220 : A map = ReadTaggedPointerField(obj, kHeapObjectMapOffset);
221 8863628 : return ReadRawField<uint16_t>(map, kMapInstanceTypeOffset);
222 : }
223 :
224 : V8_INLINE static int GetOddballKind(const internal::Address obj) {
225 : return SmiValue(ReadTaggedSignedField(obj, kOddballKindOffset));
226 : }
227 :
228 : V8_INLINE static bool IsExternalTwoByteString(int instance_type) {
229 31 : int representation = (instance_type & kFullStringRepresentationMask);
230 : return representation == kExternalTwoByteRepresentationTag;
231 : }
232 :
233 : V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) {
234 : uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
235 46 : return *addr & static_cast<uint8_t>(1U << shift);
236 : }
237 :
238 : V8_INLINE static void UpdateNodeFlag(internal::Address* obj, bool value,
239 : int shift) {
240 : uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
241 : uint8_t mask = static_cast<uint8_t>(1U << shift);
242 105054 : *addr = static_cast<uint8_t>((*addr & ~mask) | (value << shift));
243 : }
244 :
245 : V8_INLINE static uint8_t GetNodeState(internal::Address* obj) {
246 : uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
247 20 : return *addr & kNodeStateMask;
248 : }
249 :
250 : V8_INLINE static void UpdateNodeState(internal::Address* obj, uint8_t value) {
251 : uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
252 : *addr = static_cast<uint8_t>((*addr & ~kNodeStateMask) | value);
253 : }
254 :
255 : V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, uint32_t slot,
256 : void* data) {
257 50 : internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
258 40 : kIsolateEmbedderDataOffset +
259 90 : slot * kApiSystemPointerSize;
260 60467 : *reinterpret_cast<void**>(addr) = data;
261 : }
262 :
263 : V8_INLINE static void* GetEmbedderData(const v8::Isolate* isolate,
264 : uint32_t slot) {
265 100 : internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
266 60 : kIsolateEmbedderDataOffset +
267 160 : slot * kApiSystemPointerSize;
268 345262 : return *reinterpret_cast<void* const*>(addr);
269 : }
270 :
271 : V8_INLINE static internal::Address* GetRoot(v8::Isolate* isolate, int index) {
272 : internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
273 2246726 : kIsolateRootsOffset +
274 6692286 : index * kApiSystemPointerSize;
275 5776374 : return reinterpret_cast<internal::Address*>(addr);
276 : }
277 :
278 : template <typename T>
279 : V8_INLINE static T ReadRawField(internal::Address heap_object_ptr,
280 : int offset) {
281 58995699 : internal::Address addr = heap_object_ptr + offset - kHeapObjectTag;
282 58995699 : return *reinterpret_cast<const T*>(addr);
283 : }
284 :
285 : V8_INLINE static internal::Address ReadTaggedPointerField(
286 : internal::Address heap_object_ptr, int offset) {
287 : #ifdef V8_COMPRESS_POINTERS
288 : int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
289 : internal::Address root = GetRootFromOnHeapAddress(heap_object_ptr);
290 : return root + static_cast<internal::Address>(static_cast<intptr_t>(value));
291 : #else
292 : return ReadRawField<internal::Address>(heap_object_ptr, offset);
293 : #endif
294 : }
295 :
296 : V8_INLINE static internal::Address ReadTaggedSignedField(
297 : internal::Address heap_object_ptr, int offset) {
298 : #ifdef V8_COMPRESS_POINTERS
299 : int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
300 : return static_cast<internal::Address>(static_cast<intptr_t>(value));
301 : #else
302 : return ReadRawField<internal::Address>(heap_object_ptr, offset);
303 : #endif
304 : }
305 :
306 : V8_INLINE static internal::Address ReadTaggedAnyField(
307 : internal::Address heap_object_ptr, int offset) {
308 : #ifdef V8_COMPRESS_POINTERS
309 : int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
310 : internal::Address root_mask = static_cast<internal::Address>(
311 : -static_cast<intptr_t>(value & kSmiTagMask));
312 : internal::Address root_or_zero =
313 : root_mask & GetRootFromOnHeapAddress(heap_object_ptr);
314 : return root_or_zero +
315 : static_cast<internal::Address>(static_cast<intptr_t>(value));
316 : #else
317 : return ReadRawField<internal::Address>(heap_object_ptr, offset);
318 : #endif
319 : }
320 :
321 : #ifdef V8_COMPRESS_POINTERS
322 : static constexpr size_t kPtrComprHeapReservationSize = size_t{1} << 32;
323 : static constexpr size_t kPtrComprIsolateRootBias =
324 : kPtrComprHeapReservationSize / 2;
325 : static constexpr size_t kPtrComprIsolateRootAlignment = size_t{1} << 32;
326 :
327 : V8_INLINE static internal::Address GetRootFromOnHeapAddress(
328 : internal::Address addr) {
329 : return (addr + kPtrComprIsolateRootBias) &
330 : -static_cast<intptr_t>(kPtrComprIsolateRootAlignment);
331 : }
332 :
333 : #else
334 :
335 : template <typename T>
336 : V8_INLINE static T ReadEmbedderData(const v8::Context* context, int index) {
337 : typedef internal::Address A;
338 : typedef internal::Internals I;
339 183729 : A ctx = *reinterpret_cast<const A*>(context);
340 : A embedder_data =
341 : I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset);
342 : int value_offset =
343 654 : I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index);
344 : return I::ReadRawField<T>(embedder_data, value_offset);
345 : }
346 : #endif // V8_COMPRESS_POINTERS
347 : };
348 :
349 : // Only perform cast check for types derived from v8::Data since
350 : // other types do not implement the Cast method.
351 : template <bool PerformCheck>
352 : struct CastCheck {
353 : template <class T>
354 : static void Perform(T* data);
355 : };
356 :
357 : template <>
358 : template <class T>
359 75 : void CastCheck<true>::Perform(T* data) {
360 : T::Cast(data);
361 75 : }
362 :
363 : template <>
364 : template <class T>
365 5 : void CastCheck<false>::Perform(T* data) {}
366 :
367 : template <class T>
368 : V8_INLINE void PerformCastCheck(T* data) {
369 80 : CastCheck<std::is_base_of<Data, T>::value>::Perform(data);
370 : }
371 :
372 : // {obj} must be the raw tagged pointer representation of a HeapObject
373 : // that's guaranteed to never be in ReadOnlySpace.
374 : V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);
375 :
376 : // Returns if we need to throw when an error occurs. This infers the language
377 : // mode based on the current context and the closure. This returns true if the
378 : // language mode is strict.
379 : V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate);
380 :
381 : } // namespace internal
382 : } // namespace v8
383 :
384 : #endif // INCLUDE_V8_INTERNAL_H_
|