| // 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 V8_OBJECTS_INSTANCE_TYPE_INL_H_ |
| #define V8_OBJECTS_INSTANCE_TYPE_INL_H_ |
| |
| #include "src/objects/instance-type.h" |
| // Include the non-inl header before the rest of the headers. |
| |
| #include <optional> |
| |
| #include "src/base/bounds.h" |
| #include "src/common/ptr-compr-inl.h" |
| #include "src/objects/instance-type-checker.h" |
| #include "src/objects/map.h" |
| |
| // Has to be the last include (doesn't have include guards): |
| #include "src/objects/object-macros.h" |
| |
| namespace v8::internal { |
| |
| constexpr std::optional<RootIndex> Map::TryGetMapRootIdxFor(InstanceType type) { |
| switch (type) { |
| #define MAKE_CASE(TYPE, Name, name) \ |
| case TYPE: \ |
| return RootIndex::k##Name##Map; |
| STRUCT_LIST(MAKE_CASE) |
| #undef MAKE_CASE |
| case DESCRIPTOR_ARRAY_TYPE: |
| return RootIndex::kDescriptorArrayMap; |
| case ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE: |
| return RootIndex::kOnHeapBasicBlockProfilerDataMap; |
| case TURBOFAN_BITSET_TYPE_TYPE: |
| return RootIndex::kTurbofanBitsetTypeMap; |
| case TURBOFAN_UNION_TYPE_TYPE: |
| return RootIndex::kTurbofanUnionTypeMap; |
| case TURBOFAN_RANGE_TYPE_TYPE: |
| return RootIndex::kTurbofanRangeTypeMap; |
| case TURBOFAN_HEAP_CONSTANT_TYPE_TYPE: |
| return RootIndex::kTurbofanHeapConstantTypeMap; |
| case TURBOFAN_OTHER_NUMBER_CONSTANT_TYPE_TYPE: |
| return RootIndex::kTurbofanOtherNumberConstantTypeMap; |
| case TURBOSHAFT_WORD32_RANGE_TYPE_TYPE: |
| return RootIndex::kTurboshaftWord32RangeTypeMap; |
| case TURBOSHAFT_WORD32_SET_TYPE_TYPE: |
| return RootIndex::kTurboshaftWord32SetTypeMap; |
| case TURBOSHAFT_WORD64_RANGE_TYPE_TYPE: |
| return RootIndex::kTurboshaftWord64RangeTypeMap; |
| case TURBOSHAFT_WORD64_SET_TYPE_TYPE: |
| return RootIndex::kTurboshaftWord64SetTypeMap; |
| case TURBOSHAFT_FLOAT64_RANGE_TYPE_TYPE: |
| return RootIndex::kTurboshaftFloat64RangeTypeMap; |
| case TURBOSHAFT_FLOAT64_SET_TYPE_TYPE: |
| return RootIndex::kTurboshaftFloat64SetTypeMap; |
| case SORT_STATE_TYPE: |
| return RootIndex::kSortStateMap; |
| #if V8_ENABLE_WEBASSEMBLY |
| case WASM_FAST_API_CALL_DATA_TYPE: |
| return RootIndex::kWasmFastApiCallDataMap; |
| case WASM_STRING_VIEW_ITER_TYPE: |
| return RootIndex::kWasmStringViewIterMap; |
| #endif // V8_ENABLE_WEBASSEMBLY |
| default: |
| break; |
| } |
| return {}; |
| } |
| |
| namespace InstanceTypeChecker { |
| |
| // INSTANCE_TYPE_CHECKERS macro defines some "types" that do not have |
| // respective C++ classes (see TypedArrayConstructor, FixedArrayExact) or |
| // the respective C++ counterpart is actually a template (see HashTable). |
| // So in order to be able to customize IsType() implementations for specific |
| // types, we declare a parallel set of "types" that can be compared using |
| // std::is_same<>. |
| namespace InstanceTypeTraits { |
| |
| #define DECL_TYPE(type, ...) class type; |
| INSTANCE_TYPE_CHECKERS(DECL_TYPE) |
| INSTANCE_TYPE_LIST_MULTIPLE(DECL_TYPE) |
| HEAP_OBJECT_TYPE_LIST(DECL_TYPE) |
| #undef DECL_TYPE |
| |
| } // namespace InstanceTypeTraits |
| |
| // Instance types which are associated with one unique map. |
| |
| template <class type> |
| V8_INLINE consteval std::optional<RootIndex> UniqueMapOfInstanceTypeCheck() { |
| return {}; |
| } |
| |
| #define INSTANCE_TYPE_MAP(V, rootIndexName, rootAccessorName, class_name) \ |
| template <> \ |
| V8_INLINE consteval std::optional<RootIndex> \ |
| UniqueMapOfInstanceTypeCheck<InstanceTypeTraits::class_name>() { \ |
| return {RootIndex::k##rootIndexName}; \ |
| } |
| UNIQUE_INSTANCE_TYPE_MAP_LIST_GENERATOR(INSTANCE_TYPE_MAP, _) |
| #undef INSTANCE_TYPE_MAP |
| |
| V8_INLINE constexpr std::optional<RootIndex> UniqueMapOfInstanceType( |
| InstanceType type) { |
| #define INSTANCE_TYPE_CHECK(it, forinstancetype) \ |
| if (type == forinstancetype) { \ |
| return InstanceTypeChecker::UniqueMapOfInstanceTypeCheck< \ |
| InstanceTypeChecker::InstanceTypeTraits::it>(); \ |
| } |
| INSTANCE_TYPE_CHECKERS_SINGLE(INSTANCE_TYPE_CHECK); |
| #undef INSTANCE_TYPE_CHECK |
| |
| return Map::TryGetMapRootIdxFor(type); |
| } |
| |
| // Manually curated list of instance type ranges which are associated with a |
| // unique range of map addresses on the read only heap. Both ranges are |
| // inclusive. |
| |
| using InstanceTypeRange = std::pair<InstanceType, InstanceType>; |
| using TaggedAddressRange = std::pair<Tagged_t, Tagged_t>; |
| |
| #if V8_STATIC_ROOTS_BOOL |
| constexpr std::array<std::pair<InstanceTypeRange, TaggedAddressRange>, 9> |
| kUniqueMapRangeOfInstanceTypeRangeList = { |
| {{{ALLOCATION_SITE_TYPE, ALLOCATION_SITE_TYPE}, |
| {StaticReadOnlyRoot::kAllocationSiteWithWeakNextMap, |
| StaticReadOnlyRoot::kAllocationSiteWithoutWeakNextMap}}, |
| {{FIRST_STRING_TYPE, LAST_STRING_TYPE}, |
| {InstanceTypeChecker::kStringMapLowerBound, |
| InstanceTypeChecker::kStringMapUpperBound}}, |
| {{FIRST_NAME_TYPE, LAST_NAME_TYPE}, |
| {InstanceTypeChecker::kStringMapLowerBound, |
| StaticReadOnlyRoot::kSymbolMap}}, |
| {{ODDBALL_TYPE, ODDBALL_TYPE}, |
| {StaticReadOnlyRoot::kUndefinedMap, StaticReadOnlyRoot::kBooleanMap}}, |
| {{HEAP_NUMBER_TYPE, ODDBALL_TYPE}, |
| {StaticReadOnlyRoot::kUndefinedMap, |
| StaticReadOnlyRoot::kHeapNumberMap}}, |
| {{BIGINT_TYPE, HEAP_NUMBER_TYPE}, |
| {StaticReadOnlyRoot::kHeapNumberMap, StaticReadOnlyRoot::kBigIntMap}}, |
| {{FIRST_SMALL_ORDERED_HASH_TABLE_TYPE, |
| LAST_SMALL_ORDERED_HASH_TABLE_TYPE}, |
| {StaticReadOnlyRoot::kSmallOrderedHashMapMap, |
| StaticReadOnlyRoot::kSmallOrderedNameDictionaryMap}}, |
| {{FIRST_TURBOFAN_TYPE_TYPE, LAST_TURBOFAN_TYPE_TYPE}, |
| {StaticReadOnlyRoot::kTurbofanBitsetTypeMap, |
| StaticReadOnlyRoot::kTurbofanOtherNumberConstantTypeMap}}}}; |
| |
| struct kUniqueMapRangeOfStringType { |
| static constexpr TaggedAddressRange kSeqString = { |
| InstanceTypeChecker::kStringMapLowerBound, |
| StaticReadOnlyRoot::kInternalizedOneByteStringMap}; |
| static constexpr TaggedAddressRange kInternalizedString = { |
| StaticReadOnlyRoot::kInternalizedTwoByteStringMap, |
| StaticReadOnlyRoot::kUncachedExternalInternalizedOneByteStringMap}; |
| static constexpr TaggedAddressRange kExternalString = { |
| StaticReadOnlyRoot::kExternalInternalizedTwoByteStringMap, |
| StaticReadOnlyRoot::kExternalOneByteStringMap}; |
| static constexpr TaggedAddressRange kUncachedExternalString = { |
| StaticReadOnlyRoot::kUncachedExternalInternalizedTwoByteStringMap, |
| StaticReadOnlyRoot::kSharedUncachedExternalOneByteStringMap}; |
| static constexpr TaggedAddressRange kConsString = { |
| StaticReadOnlyRoot::kConsTwoByteStringMap, |
| StaticReadOnlyRoot::kConsOneByteStringMap}; |
| static constexpr TaggedAddressRange kSlicedString = { |
| StaticReadOnlyRoot::kSlicedTwoByteStringMap, |
| StaticReadOnlyRoot::kSlicedOneByteStringMap}; |
| static constexpr TaggedAddressRange kThinString = { |
| StaticReadOnlyRoot::kThinTwoByteStringMap, |
| StaticReadOnlyRoot::kThinOneByteStringMap}; |
| static constexpr TaggedAddressRange kSharedSeqString = { |
| InstanceTypeChecker::kStringMapLowerBound, |
| StaticReadOnlyRoot::kSharedSeqOneByteStringMap}; |
| static constexpr TaggedAddressRange kSharedExternalString = { |
| StaticReadOnlyRoot::kSharedUncachedExternalTwoByteStringMap, |
| StaticReadOnlyRoot::kSharedExternalOneByteStringMap}; |
| static constexpr TaggedAddressRange kDirectString = { |
| InstanceTypeChecker::kStringMapLowerBound, |
| StaticReadOnlyRoot::kExternalOneByteStringMap}; |
| static constexpr TaggedAddressRange kIndirectString = { |
| StaticReadOnlyRoot::kConsTwoByteStringMap, |
| StaticReadOnlyRoot::kThinOneByteStringMap}; |
| }; |
| |
| // This one is very sneaky. String maps are laid out sequentially, and |
| // alternate between two-byte and one-byte. Since they're sequential, each |
| // address is one Map::kSize larger than the previous. This means that the LSB |
| // of the map size alternates being set and unset for alternating string map |
| // addresses, and therefore is on/off for all two-byte/one-byte strings. Which |
| // of the two has the on-bit depends on the current RO heap layout, so just |
| // sniff this by checking an arbitrary one-byte map's value. |
| static constexpr uint32_t kStringMapEncodingMask = |
| 1 << base::bits::CountTrailingZerosNonZero(Map::kSize); |
| static constexpr uint32_t kOneByteStringMapBit = |
| StaticReadOnlyRoot::kSeqOneByteStringMap & kStringMapEncodingMask; |
| static constexpr uint32_t kTwoByteStringMapBit = |
| StaticReadOnlyRoot::kSeqTwoByteStringMap & kStringMapEncodingMask; |
| |
| inline constexpr std::optional<TaggedAddressRange> |
| UniqueMapRangeOfInstanceTypeRange(InstanceType first, InstanceType last) { |
| // Doesn't use range based for loop due to LLVM <11 bug re. constexpr |
| // functions. |
| for (size_t i = 0; i < kUniqueMapRangeOfInstanceTypeRangeList.size(); ++i) { |
| if (kUniqueMapRangeOfInstanceTypeRangeList[i].first.first == first && |
| kUniqueMapRangeOfInstanceTypeRangeList[i].first.second == last) { |
| return {kUniqueMapRangeOfInstanceTypeRangeList[i].second}; |
| } |
| } |
| return {}; |
| } |
| |
| inline constexpr std::optional<TaggedAddressRange> UniqueMapRangeOfInstanceType( |
| InstanceType type) { |
| return UniqueMapRangeOfInstanceTypeRange(type, type); |
| } |
| |
| inline bool MayHaveMapCheckFastCase(InstanceType type) { |
| if (UniqueMapOfInstanceType(type)) return true; |
| for (auto& el : kUniqueMapRangeOfInstanceTypeRangeList) { |
| if (el.first.first <= type && type <= el.first.second) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| inline bool CheckInstanceMap(RootIndex expected, Tagged<Map> map) { |
| return V8HeapCompressionScheme::CompressObject(map.ptr()) == |
| StaticReadOnlyRootsPointerTable[static_cast<size_t>(expected)]; |
| } |
| |
| inline constexpr bool CheckInstanceMapRange(TaggedAddressRange expected, |
| Tagged<Map> map) { |
| Tagged_t ptr = V8HeapCompressionScheme::CompressObject(map.ptr()); |
| // Make the upper limit be the end of the map object, rather than the start; |
| // this helps the C++ optimizer realize there are no "holes" between |
| // neighbouring map ranges, such as string map ranges. |
| return base::IsInRange(ptr, expected.first, expected.second + Map::kSize - 1); |
| } |
| |
| #else |
| |
| inline bool MayHaveMapCheckFastCase(InstanceType type) { return false; } |
| |
| #endif // V8_STATIC_ROOTS_BOOL |
| |
| // Define type checkers for classes with single instance type. |
| // INSTANCE_TYPE_CHECKER1 is to be used if the instance type is already loaded. |
| // INSTANCE_TYPE_CHECKER2 is preferred since it can sometimes avoid loading the |
| // instance type from the map, if the checked instance type corresponds to a |
| // known map or range of maps. |
| |
| #define INSTANCE_TYPE_CHECKER1(type, forinstancetype) \ |
| V8_INLINE constexpr bool Is##type(InstanceType instance_type) { \ |
| return instance_type == forinstancetype; \ |
| } |
| |
| #if V8_STATIC_ROOTS_BOOL |
| |
| #define INSTANCE_TYPE_CHECKER2(type, forinstancetype_) \ |
| V8_INLINE bool Is##type(Tagged<Map> map_object) { \ |
| constexpr InstanceType forinstancetype = \ |
| static_cast<InstanceType>(forinstancetype_); \ |
| if constexpr (constexpr std::optional<RootIndex> index = \ |
| UniqueMapOfInstanceType(forinstancetype)) { \ |
| return CheckInstanceMap(*index, map_object); \ |
| } \ |
| if constexpr (constexpr std::optional<TaggedAddressRange> map_range = \ |
| UniqueMapRangeOfInstanceType(forinstancetype)) { \ |
| return CheckInstanceMapRange(*map_range, map_object); \ |
| } \ |
| return Is##type(map_object->instance_type()); \ |
| } |
| |
| #else |
| |
| #define INSTANCE_TYPE_CHECKER2(type, forinstancetype) \ |
| V8_INLINE bool Is##type(Tagged<Map> map_object) { \ |
| return Is##type(map_object->instance_type()); \ |
| } |
| |
| #endif // V8_STATIC_ROOTS_BOOL |
| |
| INSTANCE_TYPE_CHECKERS_SINGLE(INSTANCE_TYPE_CHECKER1) |
| INSTANCE_TYPE_CHECKERS_SINGLE(INSTANCE_TYPE_CHECKER2) |
| #undef INSTANCE_TYPE_CHECKER1 |
| #undef INSTANCE_TYPE_CHECKER2 |
| |
| // Checks if value is in range [lower_limit, higher_limit] using a single |
| // branch. Assumes that the input instance type is valid. |
| template <InstanceType lower_limit, InstanceType upper_limit> |
| struct InstanceRangeChecker { |
| static constexpr bool Check(InstanceType value) { |
| return base::IsInRange(value, lower_limit, upper_limit); |
| } |
| }; |
| template <InstanceType upper_limit> |
| struct InstanceRangeChecker<FIRST_TYPE, upper_limit> { |
| static constexpr bool Check(InstanceType value) { |
| DCHECK_LE(FIRST_TYPE, value); |
| return value <= upper_limit; |
| } |
| }; |
| template <InstanceType lower_limit> |
| struct InstanceRangeChecker<lower_limit, LAST_TYPE> { |
| static constexpr bool Check(InstanceType value) { |
| DCHECK_GE(LAST_TYPE, value); |
| return value >= lower_limit; |
| } |
| }; |
| |
| // Define type checkers for classes with ranges of instance types. |
| // INSTANCE_TYPE_CHECKER_RANGE1 is to be used if the instance type is already |
| // loaded. INSTANCE_TYPE_CHECKER_RANGE2 is preferred since it can sometimes |
| // avoid loading the instance type from the map, if the checked instance type |
| // range corresponds to a known range of maps. |
| |
| #define INSTANCE_TYPE_CHECKER_RANGE1(type, first_instance_type, \ |
| last_instance_type) \ |
| V8_INLINE constexpr bool Is##type(InstanceType instance_type) { \ |
| return InstanceRangeChecker<first_instance_type, \ |
| last_instance_type>::Check(instance_type); \ |
| } |
| |
| #if V8_STATIC_ROOTS_BOOL |
| |
| #define INSTANCE_TYPE_CHECKER_RANGE2(type, first_instance_type, \ |
| last_instance_type) \ |
| V8_INLINE bool Is##type(Tagged<Map> map_object) { \ |
| if constexpr (constexpr std::optional<TaggedAddressRange> maybe_range = \ |
| UniqueMapRangeOfInstanceTypeRange(first_instance_type, \ |
| last_instance_type)) { \ |
| return CheckInstanceMapRange(*maybe_range, map_object); \ |
| } \ |
| return Is##type(map_object->instance_type()); \ |
| } |
| |
| #else |
| |
| #define INSTANCE_TYPE_CHECKER_RANGE2(type, first_instance_type, \ |
| last_instance_type) \ |
| V8_INLINE bool Is##type(Tagged<Map> map_object) { \ |
| return Is##type(map_object->instance_type()); \ |
| } |
| |
| #endif // V8_STATIC_ROOTS_BOOL |
| |
| INSTANCE_TYPE_CHECKERS_RANGE(INSTANCE_TYPE_CHECKER_RANGE1) |
| INSTANCE_TYPE_CHECKERS_RANGE(INSTANCE_TYPE_CHECKER_RANGE2) |
| #undef INSTANCE_TYPE_CHECKER_RANGE1 |
| #undef INSTANCE_TYPE_CHECKER_RANGE2 |
| |
| V8_INLINE constexpr bool IsHeapObject(InstanceType instance_type) { |
| return true; |
| } |
| |
| V8_INLINE constexpr bool IsInternalizedString(InstanceType instance_type) { |
| static_assert(kNotInternalizedTag != 0); |
| return (instance_type & (kIsNotStringMask | kIsNotInternalizedMask)) == |
| (kStringTag | kInternalizedTag); |
| } |
| |
| V8_INLINE bool IsInternalizedString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return CheckInstanceMapRange(kUniqueMapRangeOfStringType::kInternalizedString, |
| map_object); |
| #else |
| return IsInternalizedString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsSeqString(InstanceType instance_type) { |
| return (instance_type & (kIsNotStringMask | kStringRepresentationMask)) == |
| kSeqStringTag; |
| } |
| |
| V8_INLINE bool IsSeqString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return CheckInstanceMapRange(kUniqueMapRangeOfStringType::kSeqString, |
| map_object); |
| #else |
| return IsSeqString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsSeqOneByteString(InstanceType instance_type) { |
| return (instance_type & |
| (kIsNotStringMask | kStringRepresentationAndEncodingMask)) == |
| (kStringTag | kSeqOneByteStringTag); |
| } |
| |
| V8_INLINE bool IsSeqOneByteString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return IsSeqString(map_object) && IsOneByteString(map_object); |
| #else |
| return IsSeqOneByteString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsSeqTwoByteString(InstanceType instance_type) { |
| return (instance_type & |
| (kIsNotStringMask | kStringRepresentationAndEncodingMask)) == |
| (kStringTag | kSeqTwoByteStringTag); |
| } |
| |
| V8_INLINE bool IsSeqTwoByteString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return IsSeqString(map_object) && IsTwoByteString(map_object); |
| #else |
| return IsSeqTwoByteString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsExternalString(InstanceType instance_type) { |
| return (instance_type & (kIsNotStringMask | kStringRepresentationMask)) == |
| kExternalStringTag; |
| } |
| |
| V8_INLINE bool IsExternalString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return CheckInstanceMapRange(kUniqueMapRangeOfStringType::kExternalString, |
| map_object); |
| #else |
| return IsExternalString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsExternalOneByteString(InstanceType instance_type) { |
| return (instance_type & |
| (kIsNotStringMask | kStringRepresentationAndEncodingMask)) == |
| (kStringTag | kExternalOneByteStringTag); |
| } |
| |
| V8_INLINE bool IsExternalOneByteString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return IsExternalString(map_object) && IsOneByteString(map_object); |
| #else |
| return IsExternalOneByteString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsExternalTwoByteString(InstanceType instance_type) { |
| return (instance_type & |
| (kIsNotStringMask | kStringRepresentationAndEncodingMask)) == |
| (kStringTag | kExternalTwoByteStringTag); |
| } |
| |
| V8_INLINE bool IsExternalTwoByteString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return IsExternalString(map_object) && IsTwoByteString(map_object); |
| #else |
| return IsExternalTwoByteString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsUncachedExternalString(InstanceType instance_type) { |
| return (instance_type & (kIsNotStringMask | kUncachedExternalStringMask | |
| kStringRepresentationMask)) == |
| (kExternalStringTag | kUncachedExternalStringTag); |
| } |
| |
| V8_INLINE bool IsUncachedExternalString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return CheckInstanceMapRange( |
| kUniqueMapRangeOfStringType::kUncachedExternalString, map_object); |
| #else |
| return IsUncachedExternalString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsConsString(InstanceType instance_type) { |
| return (instance_type & (kIsNotStringMask | kStringRepresentationMask)) == |
| kConsStringTag; |
| } |
| |
| V8_INLINE bool IsConsString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return CheckInstanceMapRange(kUniqueMapRangeOfStringType::kConsString, |
| map_object); |
| #else |
| return IsConsString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsSlicedString(InstanceType instance_type) { |
| return (instance_type & (kIsNotStringMask | kStringRepresentationMask)) == |
| kSlicedStringTag; |
| } |
| |
| V8_INLINE bool IsSlicedString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return CheckInstanceMapRange(kUniqueMapRangeOfStringType::kSlicedString, |
| map_object); |
| #else |
| return IsSlicedString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsThinString(InstanceType instance_type) { |
| return (instance_type & (kIsNotStringMask | kStringRepresentationMask)) == |
| kThinStringTag; |
| } |
| |
| V8_INLINE bool IsThinString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return CheckInstanceMapRange(kUniqueMapRangeOfStringType::kThinString, |
| map_object); |
| #else |
| return IsThinString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsOneByteString(InstanceType instance_type) { |
| DCHECK(IsString(instance_type)); |
| return (instance_type & kStringEncodingMask) == kOneByteStringTag; |
| } |
| |
| V8_INLINE bool IsOneByteString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| DCHECK(IsStringMap(map_object)); |
| |
| Tagged_t ptr = V8HeapCompressionScheme::CompressObject(map_object.ptr()); |
| return (ptr & kStringMapEncodingMask) == kOneByteStringMapBit; |
| #else |
| return IsOneByteString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsTwoByteString(InstanceType instance_type) { |
| DCHECK(IsString(instance_type)); |
| return (instance_type & kStringEncodingMask) == kTwoByteStringTag; |
| } |
| |
| V8_INLINE bool IsTwoByteString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| DCHECK(IsStringMap(map_object)); |
| Tagged_t ptr = V8HeapCompressionScheme::CompressObject(map_object.ptr()); |
| return (ptr & kStringMapEncodingMask) == kTwoByteStringMapBit; |
| #else |
| return IsTwoByteString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE bool IsSharedString(InstanceType instance_type) { |
| DCHECK(IsString(instance_type)); |
| // TODO(v8:12007): Set is_shared to true on internalized string when |
| // v8_flags.shared_string_table is removed. |
| return (instance_type & kSharedStringMask) == kSharedStringTag || |
| (v8_flags.shared_string_table && IsInternalizedString(instance_type)); |
| } |
| |
| V8_INLINE bool IsSharedString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| DCHECK(IsStringMap(map_object)); |
| // TODO(v8:12007): Set is_shared to true on internalized string when |
| // v8_flags.shared_string_table is removed. |
| return (CheckInstanceMapRange(kUniqueMapRangeOfStringType::kSharedSeqString, |
| map_object) || |
| CheckInstanceMapRange( |
| kUniqueMapRangeOfStringType::kSharedExternalString, |
| map_object)) || |
| (v8_flags.shared_string_table && IsInternalizedString(map_object)); |
| #else |
| return IsSharedString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsIndirectString(InstanceType instance_type) { |
| return (instance_type & (kIsNotStringMask | kIsIndirectStringMask)) == |
| kIsIndirectStringTag; |
| } |
| |
| V8_INLINE bool IsIndirectString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return CheckInstanceMapRange(kUniqueMapRangeOfStringType::kIndirectString, |
| map_object); |
| #else |
| return IsIndirectString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsDirectString(InstanceType instance_type) { |
| return !IsIndirectString(instance_type); |
| } |
| |
| V8_INLINE bool IsDirectString(Tagged<Map> map_object) { |
| #if V8_STATIC_ROOTS_BOOL |
| return CheckInstanceMapRange(kUniqueMapRangeOfStringType::kDirectString, |
| map_object); |
| #else |
| return IsDirectString(map_object->instance_type()); |
| #endif |
| } |
| |
| V8_INLINE constexpr bool IsReferenceComparable(InstanceType instance_type) { |
| return !IsString(instance_type) && !IsBigInt(instance_type) && |
| instance_type != HEAP_NUMBER_TYPE; |
| } |
| |
| V8_INLINE constexpr bool IsGcSafeCode(InstanceType instance_type) { |
| return IsCode(instance_type); |
| } |
| |
| V8_INLINE bool IsGcSafeCode(Tagged<Map> map_object) { |
| return IsCode(map_object); |
| } |
| |
| V8_INLINE constexpr bool IsAbstractCode(InstanceType instance_type) { |
| return IsBytecodeArray(instance_type) || IsCode(instance_type); |
| } |
| |
| V8_INLINE bool IsAbstractCode(Tagged<Map> map_object) { |
| return IsAbstractCode(map_object->instance_type()); |
| } |
| |
| V8_INLINE constexpr bool IsFreeSpaceOrFiller(InstanceType instance_type) { |
| return instance_type == FREE_SPACE_TYPE || instance_type == FILLER_TYPE; |
| } |
| |
| V8_INLINE bool IsFreeSpaceOrFiller(Tagged<Map> map) { |
| #if V8_STATIC_ROOTS_BOOL |
| static_assert(StaticReadOnlyRoot::kFreeSpaceMap + Map::kSize == |
| StaticReadOnlyRoot::kOnePointerFillerMap); |
| static_assert(StaticReadOnlyRoot::kOnePointerFillerMap + Map::kSize == |
| StaticReadOnlyRoot::kTwoPointerFillerMap); |
| // Make sure that we can use fast immediate constants on arm64. |
| static_assert(StaticReadOnlyRoot::kTwoPointerFillerMap <= |
| kMaxFastImmediateConstantArm64); |
| return CheckInstanceMapRange( |
| TaggedAddressRange(StaticReadOnlyRoot::kFreeSpaceMap, |
| StaticReadOnlyRoot::kTwoPointerFillerMap), |
| map); |
| #else // !V8_STATIC_ROOTS_BOOL |
| return IsFreeSpaceOrFiller(map->instance_type()); |
| #endif // !V8_STATIC_ROOTS_BOOL |
| } |
| |
| // These JSObject types are wrappers around a set of primitive values |
| // and exist only for the purpose of passing the data across V8 Api. |
| // They are not supposed to be ever leaked to user JS code and their maps |
| // are not supposed to be ever extended or changed. |
| V8_INLINE constexpr bool IsMaybeReadOnlyJSObject(InstanceType instance_type) { |
| return IsJSExternalObject(instance_type) || IsJSMessageObject(instance_type); |
| } |
| |
| V8_INLINE bool IsMaybeReadOnlyJSObject(Tagged<Map> map_object) { |
| return IsMaybeReadOnlyJSObject(map_object->instance_type()); |
| } |
| |
| V8_INLINE constexpr bool IsPropertyDictionary(InstanceType instance_type) { |
| return instance_type == PROPERTY_DICTIONARY_TYPE; |
| } |
| |
| V8_INLINE bool IsPropertyDictionary(Tagged<Map> map_object) { |
| return IsPropertyDictionary(map_object->instance_type()); |
| } |
| |
| // Returns true for those heap object types that must be tied to some native |
| // context. |
| V8_INLINE constexpr bool IsNativeContextSpecific(InstanceType instance_type) { |
| // All context map are tied to some native context. |
| if (IsContext(instance_type)) return true; |
| // All non-JSReceivers are never tied to any native context. |
| if (!IsJSReceiver(instance_type)) return false; |
| |
| // Most of the JSReceivers are tied to some native context modulo the |
| // following exceptions. |
| if (IsMaybeReadOnlyJSObject(instance_type)) { |
| // These JSObject types are wrappers around a set of primitive values |
| // and exist only for the purpose of passing the data across V8 Api. |
| // Thus they are not tied to any native context. |
| return false; |
| } else if (InstanceTypeChecker::IsAlwaysSharedSpaceJSObject(instance_type)) { |
| // JSObjects allocated in shared space are never tied to a native context. |
| return false; |
| |
| #if V8_ENABLE_WEBASSEMBLY |
| } else if (InstanceTypeChecker::IsWasmObject(instance_type)) { |
| // Wasm structs/arrays are not tied to a native context. |
| return false; |
| #endif |
| } |
| return true; |
| } |
| |
| V8_INLINE bool IsNativeContextSpecificMap(Tagged<Map> map_object) { |
| return IsNativeContextSpecific(map_object->instance_type()); |
| } |
| |
| V8_INLINE constexpr bool IsJSApiWrapperObject(InstanceType instance_type) { |
| return IsJSAPIObjectWithEmbedderSlots(instance_type) || |
| IsJSSpecialObject(instance_type); |
| } |
| |
| V8_INLINE bool IsJSApiWrapperObject(Tagged<Map> map_object) { |
| return IsJSApiWrapperObject(map_object->instance_type()); |
| } |
| |
| V8_INLINE constexpr bool IsCppHeapPointerWrapperObject( |
| InstanceType instance_type) { |
| return IsJSApiWrapperObject(instance_type) || |
| IsCppHeapExternalObject(instance_type) || |
| IsCppGCManagedBase(instance_type) || |
| IsEmbedderDataArray(instance_type); |
| } |
| |
| V8_INLINE bool IsCppHeapPointerWrapperObject(Tagged<Map> map_object) { |
| return IsCppHeapPointerWrapperObject(map_object->instance_type()); |
| } |
| |
| } // namespace InstanceTypeChecker |
| |
| #define TYPE_CHECKER(type, ...) \ |
| inline bool Is##type##Map(Tagged<Map> map) { \ |
| return InstanceTypeChecker::Is##type(map); \ |
| } |
| |
| INSTANCE_TYPE_CHECKERS(TYPE_CHECKER) |
| #undef TYPE_CHECKER |
| |
| } // namespace v8::internal |
| |
| #include "src/objects/object-macros-undef.h" |
| |
| #endif // V8_OBJECTS_INSTANCE_TYPE_INL_H_ |