v8-internal.h 14.2 KB
Newer Older
1 2 3 4 5 6 7 8 9
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef INCLUDE_V8_INTERNAL_H_
#define INCLUDE_V8_INTERNAL_H_

#include <stddef.h>
#include <stdint.h>
10
#include <string.h>
11 12 13 14 15 16 17 18 19 20 21 22 23
#include <type_traits>

#include "v8-version.h"  // NOLINT(build/include)
#include "v8config.h"    // NOLINT(build/include)

namespace v8 {

class Context;
class Data;
class Isolate;

namespace internal {

24 25
class Isolate;

26 27
typedef uintptr_t Address;
static const Address kNullAddress = 0;
28 29 30 31

/**
 * Configuration of tagging scheme.
 */
32 33
const int kApiSystemPointerSize = sizeof(void*);
const int kApiDoubleSize = sizeof(double);
34
const int kApiInt32Size = sizeof(int32_t);
35
const int kApiInt64Size = sizeof(int64_t);
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

// Tag information for HeapObject.
const int kHeapObjectTag = 1;
const int kWeakHeapObjectTag = 3;
const int kHeapObjectTagSize = 2;
const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1;

// Tag information for Smi.
const int kSmiTag = 0;
const int kSmiTagSize = 1;
const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1;

template <size_t tagged_ptr_size>
struct SmiTagging;

51 52 53 54
constexpr intptr_t kIntptrAllBitsSet = intptr_t{-1};
constexpr uintptr_t kUintptrAllBitsSet =
    static_cast<uintptr_t>(kIntptrAllBitsSet);

55 56 57 58
// Smi constants for systems where tagged pointer is a 32-bit value.
template <>
struct SmiTagging<4> {
  enum { kSmiShiftSize = 0, kSmiValueSize = 31 };
59 60 61 62 63

  static constexpr intptr_t kSmiMinValue =
      static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1));
  static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1);

64
  V8_INLINE static int SmiToInt(const internal::Address value) {
65
    int shift_bits = kSmiTagSize + kSmiShiftSize;
66 67
    // Shift down (requires >> to be sign extending).
    return static_cast<int>(static_cast<intptr_t>(value)) >> shift_bits;
68 69
  }
  V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
70 71 72 73 74 75 76
    // Is value in range [kSmiMinValue, kSmiMaxValue].
    // Use unsigned operations in order to avoid undefined behaviour in case of
    // signed integer overflow.
    return (static_cast<uintptr_t>(value) -
            static_cast<uintptr_t>(kSmiMinValue)) <=
           (static_cast<uintptr_t>(kSmiMaxValue) -
            static_cast<uintptr_t>(kSmiMinValue));
77 78 79 80 81 82 83
  }
};

// Smi constants for systems where tagged pointer is a 64-bit value.
template <>
struct SmiTagging<8> {
  enum { kSmiShiftSize = 31, kSmiValueSize = 32 };
84 85 86 87 88

  static constexpr intptr_t kSmiMinValue =
      static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1));
  static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1);

89
  V8_INLINE static int SmiToInt(const internal::Address value) {
90 91
    int shift_bits = kSmiTagSize + kSmiShiftSize;
    // Shift down and throw away top 32 bits.
92
    return static_cast<int>(static_cast<intptr_t>(value) >> shift_bits);
93 94 95 96 97 98 99
  }
  V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
    // To be representable as a long smi, the value must be a 32-bit integer.
    return (value == static_cast<int32_t>(value));
  }
};

100
#ifdef V8_COMPRESS_POINTERS
101
static_assert(
102
    kApiSystemPointerSize == kApiInt64Size,
103
    "Pointer compression can be enabled only for 64-bit architectures");
104 105 106
const int kApiTaggedSize = kApiInt32Size;
#else
const int kApiTaggedSize = kApiSystemPointerSize;
107 108
#endif

109
#ifdef V8_31BIT_SMIS_ON_64BIT_ARCH
110
using PlatformSmiTagging = SmiTagging<kApiInt32Size>;
111
#else
112
using PlatformSmiTagging = SmiTagging<kApiTaggedSize>;
113
#endif
114 115 116

const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize;
const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize;
117 118
const int kSmiMinValue = static_cast<int>(PlatformSmiTagging::kSmiMinValue);
const int kSmiMaxValue = static_cast<int>(PlatformSmiTagging::kSmiMaxValue);
119 120 121
constexpr bool SmiValuesAre31Bits() { return kSmiValueSize == 31; }
constexpr bool SmiValuesAre32Bits() { return kSmiValueSize == 32; }

122 123 124 125 126
V8_INLINE static constexpr internal::Address IntToSmi(int value) {
  return (static_cast<Address>(value) << (kSmiTagSize + kSmiShiftSize)) |
         kSmiTag;
}

127 128 129 130 131 132 133 134 135 136
/**
 * This class exports constants and functionality from within v8 that
 * is necessary to implement inline functions in the v8 api.  Don't
 * depend on functions and constants defined here.
 */
class Internals {
 public:
  // These values match non-compiler-dependent values defined within
  // the implementation of v8.
  static const int kHeapObjectMapOffset = 0;
137 138 139
  static const int kMapInstanceTypeOffset = 1 * kApiTaggedSize + kApiInt32Size;
  static const int kStringResourceOffset =
      1 * kApiTaggedSize + 2 * kApiInt32Size;
140 141 142 143 144 145

  static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize;
  static const int kForeignAddressOffset = kApiTaggedSize;
  static const int kJSObjectHeaderSize = 3 * kApiTaggedSize;
  static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize;
  static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize;
146
  static const int kEmbedderDataSlotSize = kApiSystemPointerSize;
147
  static const int kNativeContextEmbedderDataOffset = 7 * kApiTaggedSize;
148 149 150 151 152
  static const int kFullStringRepresentationMask = 0x0f;
  static const int kStringEncodingMask = 0x8;
  static const int kExternalTwoByteRepresentationTag = 0x02;
  static const int kExternalOneByteRepresentationTag = 0x0a;

153 154
  static const uint32_t kNumIsolateDataSlots = 4;

155
  // IsolateData layout guarantees.
156
  static const int kIsolateEmbedderDataOffset = 0;
157
  static const int kExternalMemoryOffset =
158
      kNumIsolateDataSlots * kApiSystemPointerSize;
159 160 161 162
  static const int kExternalMemoryLimitOffset =
      kExternalMemoryOffset + kApiInt64Size;
  static const int kExternalMemoryAtLastMarkCompactOffset =
      kExternalMemoryLimitOffset + kApiInt64Size;
163
  static const int kIsolateFastCCallCallerFpOffset =
164
      kExternalMemoryAtLastMarkCompactOffset + kApiInt64Size;
165 166 167 168 169 170
  static const int kIsolateFastCCallCallerPcOffset =
      kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize;
  static const int kIsolateStackGuardOffset =
      kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize;
  static const int kIsolateRootsOffset =
      kIsolateStackGuardOffset + 7 * kApiSystemPointerSize;
171

172 173 174 175 176 177 178
  static const int kUndefinedValueRootIndex = 4;
  static const int kTheHoleValueRootIndex = 5;
  static const int kNullValueRootIndex = 6;
  static const int kTrueValueRootIndex = 7;
  static const int kFalseValueRootIndex = 8;
  static const int kEmptyStringRootIndex = 9;

179 180
  static const int kNodeClassIdOffset = 1 * kApiSystemPointerSize;
  static const int kNodeFlagsOffset = 1 * kApiSystemPointerSize + 3;
181 182 183 184
  static const int kNodeStateMask = 0x7;
  static const int kNodeStateIsWeakValue = 2;
  static const int kNodeStateIsPendingValue = 3;

185 186
  static const int kFirstNonstringType = 0x40;
  static const int kOddballType = 0x43;
187
  static const int kForeignType = 0x46;
188 189 190 191 192 193 194
  static const int kJSSpecialApiObjectType = 0x410;
  static const int kJSApiObjectType = 0x420;
  static const int kJSObjectType = 0x421;

  static const int kUndefinedOddballKind = 5;
  static const int kNullOddballKind = 3;

195 196 197 198 199 200
  // Constants used by PropertyCallbackInfo to check if we should throw when an
  // error occurs.
  static const int kThrowOnError = 0;
  static const int kDontThrow = 1;
  static const int kInferShouldThrowMode = 2;

201 202 203 204 205 206 207 208 209 210 211
  // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an
  // incremental GC once the external memory reaches this limit.
  static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024;

  V8_EXPORT static void CheckInitializedImpl(v8::Isolate* isolate);
  V8_INLINE static void CheckInitialized(v8::Isolate* isolate) {
#ifdef V8_ENABLE_CHECKS
    CheckInitializedImpl(isolate);
#endif
  }

212 213
  V8_INLINE static bool HasHeapObjectTag(const internal::Address value) {
    return (value & kHeapObjectTagMask) == static_cast<Address>(kHeapObjectTag);
214 215
  }

216
  V8_INLINE static int SmiValue(const internal::Address value) {
217 218 219
    return PlatformSmiTagging::SmiToInt(value);
  }

220 221
  V8_INLINE static constexpr internal::Address IntToSmi(int value) {
    return internal::IntToSmi(value);
222 223 224 225 226 227
  }

  V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
    return PlatformSmiTagging::IsValidSmi(value);
  }

228 229
  V8_INLINE static int GetInstanceType(const internal::Address obj) {
    typedef internal::Address A;
230 231
    A map = ReadTaggedPointerField(obj, kHeapObjectMapOffset);
    return ReadRawField<uint16_t>(map, kMapInstanceTypeOffset);
232 233
  }

234
  V8_INLINE static int GetOddballKind(const internal::Address obj) {
235
    return SmiValue(ReadTaggedSignedField(obj, kOddballKindOffset));
236 237 238 239 240 241 242
  }

  V8_INLINE static bool IsExternalTwoByteString(int instance_type) {
    int representation = (instance_type & kFullStringRepresentationMask);
    return representation == kExternalTwoByteRepresentationTag;
  }

243
  V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) {
244 245 246 247
    uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
    return *addr & static_cast<uint8_t>(1U << shift);
  }

248
  V8_INLINE static void UpdateNodeFlag(internal::Address* obj, bool value,
249 250 251 252 253 254
                                       int shift) {
    uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
    uint8_t mask = static_cast<uint8_t>(1U << shift);
    *addr = static_cast<uint8_t>((*addr & ~mask) | (value << shift));
  }

255
  V8_INLINE static uint8_t GetNodeState(internal::Address* obj) {
256 257 258 259
    uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
    return *addr & kNodeStateMask;
  }

260
  V8_INLINE static void UpdateNodeState(internal::Address* obj, uint8_t value) {
261 262 263 264 265 266
    uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
    *addr = static_cast<uint8_t>((*addr & ~kNodeStateMask) | value);
  }

  V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, uint32_t slot,
                                        void* data) {
267 268
    internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
                             kIsolateEmbedderDataOffset +
269
                             slot * kApiSystemPointerSize;
270 271 272 273 274
    *reinterpret_cast<void**>(addr) = data;
  }

  V8_INLINE static void* GetEmbedderData(const v8::Isolate* isolate,
                                         uint32_t slot) {
275 276
    internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
                             kIsolateEmbedderDataOffset +
277
                             slot * kApiSystemPointerSize;
278 279 280
    return *reinterpret_cast<void* const*>(addr);
  }

281
  V8_INLINE static internal::Address* GetRoot(v8::Isolate* isolate, int index) {
282 283 284 285
    internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
                             kIsolateRootsOffset +
                             index * kApiSystemPointerSize;
    return reinterpret_cast<internal::Address*>(addr);
286 287 288
  }

  template <typename T>
289 290
  V8_INLINE static T ReadRawField(internal::Address heap_object_ptr,
                                  int offset) {
291
    internal::Address addr = heap_object_ptr + offset - kHeapObjectTag;
292 293 294 295 296 297 298 299 300 301 302
#ifdef V8_COMPRESS_POINTERS
    if (sizeof(T) > kApiTaggedSize) {
      // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
      // fields (external pointers, doubles and BigInt data) are only
      // kTaggedSize aligned so we have to use unaligned pointer friendly way of
      // accessing them in order to avoid undefined behavior in C++ code.
      T r;
      memcpy(&r, reinterpret_cast<void*>(addr), sizeof(T));
      return r;
    }
#endif
303 304 305
    return *reinterpret_cast<const T*>(addr);
  }

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
  V8_INLINE static internal::Address ReadTaggedPointerField(
      internal::Address heap_object_ptr, int offset) {
#ifdef V8_COMPRESS_POINTERS
    int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
    internal::Address root = GetRootFromOnHeapAddress(heap_object_ptr);
    return root + static_cast<internal::Address>(static_cast<intptr_t>(value));
#else
    return ReadRawField<internal::Address>(heap_object_ptr, offset);
#endif
  }

  V8_INLINE static internal::Address ReadTaggedSignedField(
      internal::Address heap_object_ptr, int offset) {
#ifdef V8_COMPRESS_POINTERS
    int32_t value = ReadRawField<int32_t>(heap_object_ptr, offset);
    return static_cast<internal::Address>(static_cast<intptr_t>(value));
#else
    return ReadRawField<internal::Address>(heap_object_ptr, offset);
#endif
  }

#ifdef V8_COMPRESS_POINTERS
328
  // See v8:7703 or src/ptr-compr.* for details about pointer compression.
329 330 331 332 333 334 335 336 337 338 339
  static constexpr size_t kPtrComprHeapReservationSize = size_t{1} << 32;
  static constexpr size_t kPtrComprIsolateRootBias =
      kPtrComprHeapReservationSize / 2;
  static constexpr size_t kPtrComprIsolateRootAlignment = size_t{1} << 32;

  V8_INLINE static internal::Address GetRootFromOnHeapAddress(
      internal::Address addr) {
    return (addr + kPtrComprIsolateRootBias) &
           -static_cast<intptr_t>(kPtrComprIsolateRootAlignment);
  }

340 341 342 343 344 345 346 347
  V8_INLINE static internal::Address DecompressTaggedAnyField(
      internal::Address heap_object_ptr, int32_t value) {
    internal::Address root_mask = static_cast<internal::Address>(
        -static_cast<intptr_t>(value & kSmiTagMask));
    internal::Address root_or_zero =
        root_mask & GetRootFromOnHeapAddress(heap_object_ptr);
    return root_or_zero +
           static_cast<internal::Address>(static_cast<intptr_t>(value));
348
  }
349
#endif  // V8_COMPRESS_POINTERS
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
};

// Only perform cast check for types derived from v8::Data since
// other types do not implement the Cast method.
template <bool PerformCheck>
struct CastCheck {
  template <class T>
  static void Perform(T* data);
};

template <>
template <class T>
void CastCheck<true>::Perform(T* data) {
  T::Cast(data);
}

template <>
template <class T>
void CastCheck<false>::Perform(T* data) {}

template <class T>
V8_INLINE void PerformCastCheck(T* data) {
  CastCheck<std::is_base_of<Data, T>::value>::Perform(data);
}

375 376 377 378
// {obj} must be the raw tagged pointer representation of a HeapObject
// that's guaranteed to never be in ReadOnlySpace.
V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);

379 380 381 382 383
// Returns if we need to throw when an error occurs. This infers the language
// mode based on the current context and the closure. This returns true if the
// language mode is strict.
V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate);

384 385 386 387
}  // namespace internal
}  // namespace v8

#endif  // INCLUDE_V8_INTERNAL_H_