current commit
261007.21 · deps: update V8 to 15.5.35.20
// Copyright 2012 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_OBJECTS_INL_H_
#define V8_OBJECTS_OBJECTS_INL_H_

// Review notes:
//
// - The use of macros in these inline functions may seem superfluous
// but it is absolutely needed to make sure gcc generates optimal
// code. gcc is not happy when attempting to inline too deep.

#include "src/objects/objects.h"
// Include the non-inl header before the rest of the headers.

#include "include/v8-internal.h"
#include "src/base/bits.h"
#include "src/base/bounds.h"
#include "src/base/memory.h"
#include "src/base/numbers/double.h"
#include "src/base/strong-alias.h"
#include "src/builtins/builtins.h"
#include "src/common/globals.h"
#include "src/common/ptr-compr-inl.h"
#include "src/handles/handles-inl.h"
#include "src/heap/factory.h"
#include "src/heap/heap-layout-inl.h"
#include "src/heap/heap-verifier.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/heap/read-only-heap-inl.h"
#include "src/numbers/conversions-inl.h"
#include "src/objects/allocation-site.h"
#include "src/objects/bigint.h"
#include "src/objects/casting.h"
#include "src/objects/contexts-inl.h"
#include "src/objects/deoptimization-data.h"
#include "src/objects/descriptor-array.h"
#include "src/objects/field-type.h"
#include "src/objects/foreign.h"
#include "src/objects/heap-number-inl.h"
#include "src/objects/heap-object-inl.h"
#include "src/objects/hole.h"
#include "src/objects/instance-type-checker.h"
#include "src/objects/js-proxy.h"
#include "src/objects/keys.h"
#include "src/objects/literal-objects.h"
#include "src/objects/map-word-inl.h"
#include "src/objects/number-string-cache-inl.h"
#include "src/objects/object-list-macros.h"
#include "src/objects/object-predicates-inl.h"
#include "src/objects/oddball-inl.h"
#include "src/objects/property-details-inl.h"
#include "src/objects/property.h"
#include "src/objects/regexp-match-info-inl.h"
#include "src/objects/scope-info-inl.h"
#include "src/objects/shared-function-info.h"
#include "src/objects/smi-inl.h"
#include "src/objects/tagged-field-inl.h"
#include "src/objects/tagged-impl-inl.h"
#include "src/objects/tagged-index.h"
#include "src/objects/templates-inl.h"
#include "src/objects/trusted-pointer-inl.h"
#include "src/roots/roots.h"
#include "src/sandbox/isolate-inl.h"

// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"

namespace v8 {
namespace internal {

template <typename T>
class Managed;
template <typename T>
class TrustedManaged;

// TODO(jkummerow): Most DEF_CAST_TRAITS(Foo) macro invocations should move to
// wherever `IsFoo(Tagged<HeapObject>)` is defined.
// TODO(leszeks): Expand Is<T> to all types.

DEF_CAST_TRAITS(AbstractCode)
DEF_CAST_TRAITS(AccessorInfo)
DEF_CAST_TRAITS(AllocationSite)
DEF_CAST_TRAITS(BigInt)
DEF_CAST_TRAITS(BigIntBase)
DEF_CAST_TRAITS(Boolean)
DEF_CAST_TRAITS(Cell)
DEF_CAST_TRAITS(CompilationCacheTable)
DEF_CAST_TRAITS(Context)
DEF_CAST_TRAITS(ContextCell)
DEF_CAST_TRAITS(CoverageInfo)
DEF_CAST_TRAITS(CppHeapExternalObject)
DEF_CAST_TRAITS(CppGCManagedBase)
DEF_CAST_TRAITS(DataHandler)
DEF_CAST_TRAITS(DeoptimizationData)
DEF_CAST_TRAITS(DescriptorArray)
DEF_CAST_TRAITS(DictionaryTemplateInfo)
DEF_CAST_TRAITS(EmbedderDataArray)
DEF_CAST_TRAITS(EphemeronHashTable)
DEF_CAST_TRAITS(FeedbackCell)
DEF_CAST_TRAITS(FeedbackMetadata)
DEF_CAST_TRAITS(FeedbackVector)
DEF_CAST_TRAITS(FixedArrayBase)
DEF_CAST_TRAITS(FixedArrayExact)
DEF_CAST_TRAITS(Foreign)
DEF_CAST_TRAITS(GcSafeCode)
DEF_CAST_TRAITS(GlobalDictionary)
DEF_CAST_TRAITS(HashSeedWrapper)
DEF_CAST_TRAITS(InterceptorInfo)
DEF_CAST_TRAITS(JSArgumentsObject)
DEF_CAST_TRAITS(JSArray)
DEF_CAST_TRAITS(JSArrayBuffer)
DEF_CAST_TRAITS(JSArrayBufferView)
DEF_CAST_TRAITS(JSArrayIterator)
DEF_CAST_TRAITS(JSAsyncFromSyncIterator)
DEF_CAST_TRAITS(JSAsyncFunctionObject)
DEF_CAST_TRAITS(JSAsyncGeneratorObject)
DEF_CAST_TRAITS(JSAtomicsCondition)
DEF_CAST_TRAITS(JSAtomicsMutex)
DEF_CAST_TRAITS(JSBoundFunction)
DEF_CAST_TRAITS(JSCollection)
DEF_CAST_TRAITS(JSCollectionIterator)
DEF_CAST_TRAITS(JSCustomElementsObject)
DEF_CAST_TRAITS(JSDataView)
DEF_CAST_TRAITS(JSDataViewOrRabGsabDataView)
DEF_CAST_TRAITS(JSDate)
DEF_CAST_TRAITS(JSDisposableStackBase)
DEF_CAST_TRAITS(JSSyncDisposableStack)
DEF_CAST_TRAITS(JSAsyncDisposableStack)
DEF_CAST_TRAITS(JSExternalObject)
DEF_CAST_TRAITS(JSFinalizationRegistry)
DEF_CAST_TRAITS(JSFunction)
DEF_CAST_TRAITS(JSFunctionWithoutPrototype)
DEF_CAST_TRAITS(JSFunctionWithPrototype)
DEF_CAST_TRAITS(JSFunctionOrBoundFunctionOrWrappedFunction)
DEF_CAST_TRAITS(JSGeneratorObject)
DEF_CAST_TRAITS(JSGlobalObject)
DEF_CAST_TRAITS(JSGlobalProxy)
DEF_CAST_TRAITS(JSIteratorHelper)
DEF_CAST_TRAITS(JSIteratorHelperSimple)
DEF_CAST_TRAITS(JSIteratorFilterHelper)
DEF_CAST_TRAITS(JSIteratorMapHelper)
DEF_CAST_TRAITS(JSIteratorTakeHelper)
DEF_CAST_TRAITS(JSIteratorDropHelper)
DEF_CAST_TRAITS(JSIteratorFlatMapHelper)
DEF_CAST_TRAITS(JSIteratorConcatHelper)
DEF_CAST_TRAITS(JSIteratorZipHelper)
DEF_CAST_TRAITS(JSIteratorZipKeyedHelper)
DEF_CAST_TRAITS(JSMap)
DEF_CAST_TRAITS(JSMapIterator)
DEF_CAST_TRAITS(JSMessageObject)
DEF_CAST_TRAITS(JSModuleNamespace)
DEF_CAST_TRAITS(JSDeferredModuleNamespace)
DEF_CAST_TRAITS(JSObject)
DEF_CAST_TRAITS(JSAPIObjectWithEmbedderSlots)
DEF_CAST_TRAITS(JSObjectWithEmbedderSlots)
DEF_CAST_TRAITS(JSPrimitiveWrapper)
DEF_CAST_TRAITS(JSPromise)
DEF_CAST_TRAITS(JSRabGsabDataView)
DEF_CAST_TRAITS(JSRawJson)
DEF_CAST_TRAITS(JSReceiver)
DEF_CAST_TRAITS(JSRegExp)
DEF_CAST_TRAITS(JSRegExpStringIterator)
DEF_CAST_TRAITS(JSSet)
DEF_CAST_TRAITS(JSSetIterator)
DEF_CAST_TRAITS(JSShadowRealm)
DEF_CAST_TRAITS(JSSharedArray)
DEF_CAST_TRAITS(JSSharedStruct)
DEF_CAST_TRAITS(JSSpecialObject)
DEF_CAST_TRAITS(JSStringIterator)
DEF_CAST_TRAITS(JSSynchronizationPrimitive)
DEF_CAST_TRAITS(JSDetachedTypedArray)
DEF_CAST_TRAITS(JSTypedArray)
DEF_CAST_TRAITS(JSValidIteratorWrapper)
DEF_CAST_TRAITS(JSWeakCollection)
DEF_CAST_TRAITS(JSWeakRef)
DEF_CAST_TRAITS(JSWeakMap)
DEF_CAST_TRAITS(JSWeakSet)
DEF_CAST_TRAITS(JSWrappedFunction)
DEF_CAST_TRAITS(LoadHandler)
DEF_CAST_TRAITS(MegaDomHandler)
DEF_CAST_TRAITS(Module)
DEF_CAST_TRAITS(Microtask)
DEF_CAST_TRAITS(NameDictionary)
DEF_CAST_TRAITS(NativeContext)
DEF_CAST_TRAITS(NormalizedMapCache)
DEF_CAST_TRAITS(NumberDictionary)
DEF_CAST_TRAITS(ObjectHashSet)
DEF_CAST_TRAITS(ObjectHashTable)
DEF_CAST_TRAITS(ObjectTwoHashTable)
DEF_CAST_TRAITS(OnHeapBasicBlockProfilerData)
DEF_CAST_TRAITS(Hole)
DEF_CAST_TRAITS(OrderedHashMap)
DEF_CAST_TRAITS(OrderedHashSet)
DEF_CAST_TRAITS(OrderedNameDictionary)
DEF_CAST_TRAITS(PreparseData)
DEF_CAST_TRAITS(PrimitiveHeapObject)
DEF_CAST_TRAITS(PromiseReactionJobTask)
DEF_CAST_TRAITS(PropertyCell)
DEF_CAST_TRAITS(SharedFunctionInfo)
DEF_CAST_TRAITS(SimpleNameDictionary)
DEF_CAST_TRAITS(SimpleNumberDictionary)
DEF_CAST_TRAITS(SmallOrderedHashMap)
DEF_CAST_TRAITS(SmallOrderedHashSet)
DEF_CAST_TRAITS(SmallOrderedNameDictionary)
DEF_CAST_TRAITS(SortState)
DEF_CAST_TRAITS(SourceTextModule)
DEF_CAST_TRAITS(SourceTextModuleInfo)
DEF_CAST_TRAITS(StoreHandler)
DEF_CAST_TRAITS(StringSet)
DEF_CAST_TRAITS(RegisteredSymbolTable)
DEF_CAST_TRAITS(Struct)
DEF_CAST_TRAITS(SwissNameDictionary)
DEF_CAST_TRAITS(SyntheticModule)
DEF_CAST_TRAITS(TemplateInfo)
DEF_CAST_TRAITS(TemplateInfoWithProperties)
DEF_CAST_TRAITS(TemplateLiteralObject)
DEF_CAST_TRAITS(TransitionArray)
DEF_CAST_TRAITS(TurbofanBitsetType)
DEF_CAST_TRAITS(TurbofanHeapConstantType)
DEF_CAST_TRAITS(TurbofanOtherNumberConstantType)
DEF_CAST_TRAITS(TurbofanRangeType)
DEF_CAST_TRAITS(TurbofanType)
DEF_CAST_TRAITS(TurbofanUnionType)
DEF_CAST_TRAITS(TurboshaftFloat64RangeType)
DEF_CAST_TRAITS(TurboshaftFloat64SetType)
DEF_CAST_TRAITS(TurboshaftFloat64Type)
DEF_CAST_TRAITS(TurboshaftType)
DEF_CAST_TRAITS(TurboshaftWord32RangeType)
DEF_CAST_TRAITS(TurboshaftWord32SetType)
DEF_CAST_TRAITS(TurboshaftWord32Type)
DEF_CAST_TRAITS(TurboshaftWord64RangeType)
DEF_CAST_TRAITS(TurboshaftWord64SetType)
DEF_CAST_TRAITS(TurboshaftWord64Type)
#if V8_ENABLE_WEBASSEMBLY
DEF_CAST_TRAITS(WasmArray)
DEF_CAST_TRAITS(WasmContinuationObject)
DEF_CAST_TRAITS(WasmCustomMap)
DEF_CAST_TRAITS(WasmCustomMapWrapper)
DEF_CAST_TRAITS(WasmExceptionPackage)
DEF_CAST_TRAITS(WasmFastApiCallData)
DEF_CAST_TRAITS(WasmFuncRef)
DEF_CAST_TRAITS(WasmGlobalObject)
DEF_CAST_TRAITS(WasmInstanceObject)
DEF_CAST_TRAITS(WasmMemoryObject)
DEF_CAST_TRAITS(WasmModuleObject)
DEF_CAST_TRAITS(WasmNull)
DEF_CAST_TRAITS(WasmObject)
DEF_CAST_TRAITS(WasmResumeData)
DEF_CAST_TRAITS(WasmStackObject)
DEF_CAST_TRAITS(WasmStringViewIter)
DEF_CAST_TRAITS(WasmStruct)
DEF_CAST_TRAITS(WasmSuspendingObject)
DEF_CAST_TRAITS(WasmTableObject)
DEF_CAST_TRAITS(WasmTagObject)
DEF_CAST_TRAITS(WasmTypeInfo)
DEF_CAST_TRAITS(WasmValueObject)
#endif  // V8_ENABLE_WEBASSEMBLY
DEF_CAST_TRAITS(WeakCell)
DEF_CAST_TRAITS(ClosureFeedbackCellArray)
DEF_CAST_TRAITS(ObjectBoilerplateDescription)
DEF_CAST_TRAITS(RegExpMatchInfo)
DEF_CAST_TRAITS(ScriptContextTable)
DEF_CAST_TRAITS(SloppyArgumentsElements)
DEF_CAST_TRAITS(WeakHomomorphicFixedArray)

#ifdef V8_INTL_SUPPORT
DEF_CAST_TRAITS(JSV8BreakIterator)
DEF_CAST_TRAITS(JSCollator)
DEF_CAST_TRAITS(JSDateTimeFormat)
DEF_CAST_TRAITS(JSDisplayNames)
DEF_CAST_TRAITS(JSDurationFormat)
DEF_CAST_TRAITS(JSListFormat)
DEF_CAST_TRAITS(JSLocale)
DEF_CAST_TRAITS(JSNumberFormat)
DEF_CAST_TRAITS(JSPluralRules)
DEF_CAST_TRAITS(JSRelativeTimeFormat)
DEF_CAST_TRAITS(JSSegmentDataObject)
DEF_CAST_TRAITS(JSSegmentDataObjectWithIsWordLike)
DEF_CAST_TRAITS(JSSegmentIterator)
DEF_CAST_TRAITS(JSSegmenter)
DEF_CAST_TRAITS(JSSegments)
#endif  // V8_INTL_SUPPORT

#ifdef V8_TEMPORAL_SUPPORT
DEF_CAST_TRAITS(JSTemporalDuration)
DEF_CAST_TRAITS(JSTemporalPlainDate)
DEF_CAST_TRAITS(JSTemporalPlainTime)
DEF_CAST_TRAITS(JSTemporalPlainDateTime)
DEF_CAST_TRAITS(JSTemporalPlainMonthDay)
DEF_CAST_TRAITS(JSTemporalPlainYearMonth)
DEF_CAST_TRAITS(JSTemporalZonedDateTime)
DEF_CAST_TRAITS(JSTemporalInstant)
#endif  // V8_TEMPORAL_SUPPORT

HEAP_OBJECT_TRUSTED_TYPE_LIST(DEF_CAST_TRAITS)
HOLE_LIST(DEF_CAST_TRAITS)


DEF_CAST_TRAITS(AccessCheckNeeded)
DEF_CAST_TRAITS(AlwaysSharedSpaceJSObject)
DEF_CAST_TRAITS(BigIntWrapper)
DEF_CAST_TRAITS(BooleanWrapper)
DEF_CAST_TRAITS(Callable)
DEF_CAST_TRAITS(Constructor)
DEF_CAST_TRAITS(Filler)
DEF_CAST_TRAITS(HandlerTable)
DEF_CAST_TRAITS(JSContextExtensionObject)
DEF_CAST_TRAITS(JSError)
DEF_CAST_TRAITS(MapCache)
DEF_CAST_TRAITS(Number)
DEF_CAST_TRAITS(NumberWrapper)
DEF_CAST_TRAITS(OSROptimizedCodeCache)
DEF_CAST_TRAITS(ScriptWrapper)
DEF_CAST_TRAITS(StringWrapper)
DEF_CAST_TRAITS(SymbolWrapper)
DEF_CAST_TRAITS(UniqueName)
DEF_CAST_TRAITS(Undetectable)

template <>
struct CastTraits<JSPrimitive> {
  static inline bool AllowFrom(Tagged<Object> value) {
    return IsPrimitive(value);
  }
  static inline bool AllowFrom(Tagged<HeapObject> value) {
    return IsPrimitive(value);
  }
};
template <>
struct CastTraits<JSAny> {
  static inline bool AllowFrom(Tagged<Object> value) {
    return IsPrimitive(value) || IsJSReceiver(value);
  }
  static inline bool AllowFrom(Tagged<HeapObject> value) {
    return IsPrimitive(value) || IsJSReceiver(value);
  }
};
template <>
struct CastTraits<AllocationSiteWithWeakNext> {
  template <typename From>
  static inline bool AllowFrom(Tagged<From> value) {
    Tagged<AllocationSite> site;
    return TryCast<AllocationSite>(value, &site) && site->HasWeakNext();
  }
};

template <>
struct CastTraits<FieldType> {
  static inline bool AllowFrom(Tagged<Object> value) {
    return value == FieldType::None() || value == FieldType::Any() ||
           IsMap(value);
  }
  static inline bool AllowFrom(Tagged<HeapObject> value) {
    return IsMap(value);
  }
};

template <typename T>
struct CastTraits<Managed<T>> : public CastTraits<Foreign> {};
template <typename T>
struct CastTraits<CppGCManaged<T>> : public CastTraits<CppGCManagedBase> {};
template <typename T>
struct CastTraits<TrustedManaged<T>> : public CastTraits<TrustedForeign> {};
template <typename T>
struct CastTraits<PodArray<T>> : public CastTraits<ByteArray> {};
template <typename T>
struct CastTraits<TrustedPodArray<T>> : public CastTraits<TrustedByteArray> {};
template <typename T, typename Base>
struct CastTraits<FixedIntegerArrayBase<T, Base>> : public CastTraits<Base> {};
template <>
struct CastTraits<TrustedFixedAddressArray>
    : public CastTraits<TrustedByteArray> {};

template <>
struct CastTraits<JSRegExpResultIndices> : public CastTraits<JSArray> {};
template <>
struct CastTraits<DeoptimizationLiteralArray>
    : public CastTraits<TrustedWeakFixedArray> {};
template <>
struct CastTraits<FreshlyAllocatedBigInt> : public CastTraits<BigInt> {};
template <>
struct CastTraits<JSIteratorResult> : public CastTraits<JSObject> {};
template <>
struct CastTraits<JSUint8ArraySetFromResult> : public CastTraits<JSObject> {};

template <>
struct CastTraits<DeoptimizationFrameTranslation>
    : public CastTraits<TrustedByteArray> {};

template <class T>
T HeapObject::Relaxed_ReadField(size_t offset) const
  requires((std::is_arithmetic_v<T> || std::is_enum_v<T>) &&
           !std::is_floating_point_v<T>)
{
  // Pointer compression causes types larger than kTaggedSize to be
  // unaligned. Atomic loads must be aligned.
  DCHECK_IMPLIES(COMPRESS_POINTERS_BOOL, sizeof(T) <= kTaggedSize);
  using AtomicT = typename base::AtomicTypeFromByteWidth<sizeof(T)>::type;
  return static_cast<T>(base::AsAtomicImpl<AtomicT>::Relaxed_Load(
      reinterpret_cast<AtomicT*>(field_address(offset))));
}

template <class T>
void HeapObject::Relaxed_WriteField(size_t offset, T value)
  requires((std::is_arithmetic_v<T> || std::is_enum_v<T>) &&
           !std::is_floating_point_v<T>)
{
  // Pointer compression causes types larger than kTaggedSize to be
  // unaligned. Atomic stores must be aligned.
  DCHECK_IMPLIES(COMPRESS_POINTERS_BOOL, sizeof(T) <= kTaggedSize);
  using AtomicT = typename base::AtomicTypeFromByteWidth<sizeof(T)>::type;
  base::AsAtomicImpl<AtomicT>::Relaxed_Store(
      reinterpret_cast<AtomicT*>(field_address(offset)),
      static_cast<AtomicT>(value));
}

template <class T>
T HeapObject::Acquire_ReadField(size_t offset) const
  requires((std::is_arithmetic_v<T> || std::is_enum_v<T>) &&
           !std::is_floating_point_v<T>)
{
  // Pointer compression causes types larger than kTaggedSize to be
  // unaligned. Atomic loads must be aligned.
  DCHECK_IMPLIES(COMPRESS_POINTERS_BOOL, sizeof(T) <= kTaggedSize);
  using AtomicT = typename base::AtomicTypeFromByteWidth<sizeof(T)>::type;
  return static_cast<T>(base::AsAtomicImpl<AtomicT>::Acquire_Load(
      reinterpret_cast<AtomicT*>(field_address(offset))));
}

// static
template <typename CompareAndSwapImpl>
Tagged<Object> HeapObject::SeqCst_CompareAndSwapField(
    Tagged<Object> expected, Tagged<Object> value,
    CompareAndSwapImpl compare_and_swap_impl) {
  Tagged<Object> actual_expected = expected;
  do {
    Tagged<Object> old_value = compare_and_swap_impl(actual_expected, value);
    if (old_value == actual_expected || !IsNumber(old_value) ||
        !IsNumber(actual_expected)) {
      return old_value;
    }
    if (!Object::SameNumberValue(
            Object::NumberValue(Cast<Number>(old_value)),
            Object::NumberValue(Cast<Number>(actual_expected)))) {
      return old_value;
    }
    // The pointer comparison failed, but the numbers are equal. This can
    // happen even if both numbers are HeapNumbers with the same value.
    // Try again in the next iteration.
    actual_expected = old_value;
  } while (true);
}

constexpr bool FastInReadOnlySpaceOrSmallSmi(Tagged_t obj) {
#if V8_STATIC_ROOTS_BOOL && CONTIGUOUS_COMPRESSED_READ_ONLY_SPACE_BOOL
  // The following assert ensures that the page size check covers all our static
  // roots. This is not strictly necessary and can be relaxed in future as the
  // most prominent static roots are anyways allocated at the beginning of the
  // first page.
  // This optimization requires contiguous compressed RO space to ensure RO
  // space is at the beginning of the cage; otherwise, objects from other spaces
  // could alias with low addresses.
  constexpr int kLastStaticRootPage =
      RoundUp<kRegularPageSize>(StaticReadOnlyRoot::kLastAllocatedRoot);
  static_assert(kLastStaticRootPage <= kContiguousReadOnlyReservationSize);
  return obj < kContiguousReadOnlyReservationSize;
#else
  return false;
#endif
}

constexpr bool FastInReadOnlySpaceOrSmallSmi(Tagged<MaybeObject> obj) {
#ifdef V8_COMPRESS_POINTERS
  // This check is only valid for objects in the main cage.
  DCHECK(obj.IsSmi() || obj.IsInMainCageBase());
  return FastInReadOnlySpaceOrSmallSmi(
      V8HeapCompressionScheme::CompressAny(obj.ptr()));
#else   // V8_COMPRESS_POINTERS
  return false;
#endif  // V8_COMPRESS_POINTERS
}

bool OutsideSandboxOrInReadonlySpace(Tagged<HeapObject> obj) {
#ifdef V8_ENABLE_SANDBOX
  return OutsideSandbox(obj.address()) ||
         MemoryChunk::FromHeapObject(obj)->SandboxSafeInReadOnlySpace();
#else
  return true;
#endif
}

DEF_HEAP_OBJECT_PREDICATE(IsCallable) { return obj->map()->is_callable(); }

DEF_HEAP_OBJECT_PREDICATE(IsCallableJSProxy) {
  return IsCallable(obj) && IsJSProxy(obj);
}

DEF_HEAP_OBJECT_PREDICATE(IsCallableApiObject) {
  InstanceType type = obj->map()->instance_type();
  return IsCallable(obj) &&
         (type == JS_API_OBJECT_TYPE || type == JS_SPECIAL_API_OBJECT_TYPE);
}

DEF_HEAP_OBJECT_PREDICATE(IsNonNullForeign) {
  return IsForeign(obj) &&
         Cast<Foreign>(obj)->foreign_address_unchecked() != kNullAddress;
}

DEF_HEAP_OBJECT_PREDICATE(IsConstructor) {
  return obj->map()->is_constructor();
}

DEF_HEAP_OBJECT_PREDICATE(IsSourceTextModuleInfo) {
  return obj->map() == GetReadOnlyRoots().module_info_map();
}

DEF_HEAP_OBJECT_PREDICATE(IsTemplateLiteralObject) { return IsJSArray(obj); }

#if V8_INTL_SUPPORT
DEF_HEAP_OBJECT_PREDICATE(IsJSSegmentDataObject) { return IsJSObject(obj); }
DEF_HEAP_OBJECT_PREDICATE(IsJSSegmentDataObjectWithIsWordLike) {
  return IsJSObject(obj);
}
#endif  // V8_INTL_SUPPORT

DEF_HEAP_OBJECT_PREDICATE(IsDeoptimizationData) {
  if (!Is<ProtectedFixedArray>(obj)) return false;
  Tagged<ProtectedFixedArray> array = TrustedCast<ProtectedFixedArray>(obj);

  // There's no sure way to detect the difference between a fixed array and
  // a deoptimization data array.  Since this is used for asserts we can
  // check that the length is zero or else the fixed size plus a multiple of
  // the entry size.
  uint32_t length = array->ulength().value();
  if (length == 0) return true;

  if (length < DeoptimizationData::kFirstDeoptEntryIndex) return false;
  length -= DeoptimizationData::kFirstDeoptEntryIndex;
  return length % DeoptimizationData::kDeoptEntrySize == 0;
}

DEF_HEAP_OBJECT_PREDICATE(IsHandlerTable) { return IsFixedArrayExact(obj); }

DEF_HEAP_OBJECT_PREDICATE(IsOSROptimizedCodeCache) {
  return IsWeakFixedArray(obj);
}

DEF_HEAP_OBJECT_PREDICATE(IsStringWrapper) {
  return IsJSPrimitiveWrapper(obj) &&
         IsString(Cast<JSPrimitiveWrapper>(obj)->value());
}

DEF_HEAP_OBJECT_PREDICATE(IsBooleanWrapper) {
  return IsJSPrimitiveWrapper(obj) &&
         IsBoolean(Cast<JSPrimitiveWrapper>(obj)->value());
}

DEF_HEAP_OBJECT_PREDICATE(IsScriptWrapper) {
  return IsJSPrimitiveWrapper(obj) &&
         IsScript(Cast<JSPrimitiveWrapper>(obj)->value());
}

DEF_HEAP_OBJECT_PREDICATE(IsNumberWrapper) {
  return IsJSPrimitiveWrapper(obj) &&
         IsNumber(Cast<JSPrimitiveWrapper>(obj)->value());
}

DEF_HEAP_OBJECT_PREDICATE(IsBigIntWrapper) {
  return IsJSPrimitiveWrapper(obj) &&
         IsBigInt(Cast<JSPrimitiveWrapper>(obj)->value());
}

DEF_HEAP_OBJECT_PREDICATE(IsSymbolWrapper) {
  return IsJSPrimitiveWrapper(obj) &&
         IsSymbol(Cast<JSPrimitiveWrapper>(obj)->value());
}

DEF_HEAP_OBJECT_PREDICATE(IsStringSet) { return IsHashTable(obj); }

DEF_HEAP_OBJECT_PREDICATE(IsObjectHashSet) { return IsHashTable(obj); }

DEF_HEAP_OBJECT_PREDICATE(IsCompilationCacheTable) { return IsHashTable(obj); }

DEF_HEAP_OBJECT_PREDICATE(IsMapCache) { return IsHashTable(obj); }

DEF_HEAP_OBJECT_PREDICATE(IsObjectHashTable) { return IsHashTable(obj); }

DEF_HEAP_OBJECT_PREDICATE(IsObjectTwoHashTable) { return IsHashTable(obj); }

DEF_HEAP_OBJECT_PREDICATE(IsHashTableBase) { return IsHashTable(obj); }

// static
Maybe<bool> Object::IsArray(DirectHandle<Object> object) {
  if (IsSmi(*object)) return Just(false);
  auto heap_object = Cast<HeapObject>(object);
  if (IsJSArray(*heap_object)) return Just(true);
  if (!IsJSProxy(*heap_object)) return Just(false);
  return JSProxy::IsArray(Cast<JSProxy>(object));
}

DEF_HEAP_OBJECT_PREDICATE(IsUndetectable) {
  return obj->map()->is_undetectable();
}

DEF_HEAP_OBJECT_PREDICATE(IsAccessCheckNeeded) {
  if (IsJSGlobalProxy(obj)) {
    const Tagged<JSGlobalProxy> proxy = Cast<JSGlobalProxy>(obj);
    Isolate* isolate = Isolate::Current();
    // TODO(ishell): compare security tokens here in order to allow ICs to
    // take fast paths for cross context accesses.
    Tagged<JSGlobalObject> global = isolate->context()->global_object();
    return proxy->IsDetachedFrom(global);
  }
  return obj->map()->is_access_check_needed();
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
Maybe<double> Object::IntegerValue(Isolate* isolate, HandleType<T> input) {
  ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input));
  if (IsSmi(*input)) {
    return Just(static_cast<double>(Cast<Smi>(*input).value()));
  }
  return Just(DoubleToInteger(Cast<HeapNumber>(*input)->value()));
}

// static
bool Object::SameNumberValue(double value1, double value2) {
  // Compare values bitwise, to cover -0 being different from 0 -- we'd need to
  // look at sign bits anyway if we'd done a double comparison, so we may as
  // well compare bitwise immediately.
  uint64_t value1_bits = base::bit_cast<uint64_t>(value1);
  uint64_t value2_bits = base::bit_cast<uint64_t>(value2);
  if (value1_bits == value2_bits) {
    return true;
  }
  // SameNumberValue(NaN, NaN) is true even for NaNs with different bit
  // representations.
  return std::isnan(value1) && std::isnan(value2);
}

// static
bool IsNaN(Tagged<Object> obj) {
  return IsHeapNumber(obj) && std::isnan(Cast<HeapNumber>(obj)->value());
}

// static
bool IsMinusZero(Tagged<Object> obj) {
  return IsHeapNumber(obj) && i::IsMinusZero(Cast<HeapNumber>(obj)->value());
}

// static
bool Object::HasValidElements(Tagged<Object> obj) {
  // Dictionary is covered under FixedArray. ByteArray is used
  // for the JSTypedArray backing stores.
  return IsFixedArray(obj) || IsFixedDoubleArray(obj) || IsByteArray(obj);
}

// static
bool Object::FilterKey(Tagged<Object> obj, PropertyFilter filter) {
  DCHECK(!IsPropertyCell(obj));
  if (filter == PRIVATE_NAMES_ONLY) {
    if (!IsSymbol(obj)) return true;
    return !Cast<Symbol>(obj)->is_any_private_name();
  } else if (IsSymbol(obj)) {
    if (filter & SKIP_SYMBOLS) return true;

    if (Cast<Symbol>(obj)->is_any_private()) return true;
  } else {
    if (filter & SKIP_STRINGS) return true;
  }
  return false;
}

// static
std::pair<Representation, PropertyConstness> Object::OptimalRepresentation(
    Tagged<Object> obj, PropertyConstness constness) {
  if (IsSmi(obj)) {
    return {Representation::Smi(), constness};
  }
  Tagged<HeapObject> heap_object = Cast<HeapObject>(obj);
  if (IsUninitializedHole(heap_object)) {
    return {Representation::None(), constness};
  }
  if (IsHeapNumber(heap_object)) {
    if (constness == PropertyConstness::kConst &&
        Cast<HeapNumber>(heap_object)->is_the_hole()) {
      // Make sure that even an initializing store of a double value with
      // the hole NaN pattern removes constness, otherwise it wouldn't be
      // possible to distinguish whether subsequent stores to a double field
      // is initializing or not.
      constness = PropertyConstness::kMutable;
    }
    return {Representation::Double(), constness};
  }
  return {Representation::HeapObject(), constness};
}

// static
ElementsKind Object::OptimalElementsKind(Tagged<Object> obj) {
  if (IsSmi(obj)) return PACKED_SMI_ELEMENTS;
  Tagged<HeapObject> heap_object = Cast<HeapObject>(obj);
  if (IsHeapNumber(heap_object)) return PACKED_DOUBLE_ELEMENTS;
  // if (IsUninitializedHole(heap_object)) {
  //   return PACKED_SMI_ELEMENTS;
  // }
#ifdef V8_ENABLE_UNDEFINED_DOUBLE
  if (IsUndefined(heap_object)) {
    return HOLEY_DOUBLE_ELEMENTS;
  }
#endif  // V8_ENABLE_UNDEFINED_DOUBLE
  return PACKED_ELEMENTS;
}

// static
bool Object::FitsRepresentation(Tagged<Object> obj,
                                Representation representation,
                                bool allow_coercion) {
  if (representation.IsSmi()) {
    return IsSmi(obj);
  } else if (representation.IsDouble()) {
    return allow_coercion ? IsNumber(obj) : IsHeapNumber(obj);
  } else if (representation.IsHeapObject()) {
    return IsHeapObject(obj);
  } else if (representation.IsNone()) {
    return false;
  }
  return true;
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
typename HandleType<JSReceiver>::MaybeType Object::ToObject(
    Isolate* isolate, HandleType<T> object, const char* method_name) {
  if (V8_LIKELY(IsJSReceiver(*object))) return Cast<JSReceiver>(object);
  return ToObjectImpl(isolate, object, method_name);
}

// static
template <template <typename> typename HandleType>
typename HandleType<Name>::MaybeType Object::ToName(Isolate* isolate,
                                                    HandleType<Object> input)
  requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>)
{
  if (IsName(*input)) return Cast<Name>(input);
  return ConvertToName(isolate, input);
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
typename HandleType<Object>::MaybeType Object::ToPropertyKey(
    Isolate* isolate, HandleType<T> value) {
  if (IsSmi(*value) || IsName(Cast<HeapObject>(*value))) return value;
  return ConvertToPropertyKey(isolate, value);
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
typename HandleType<Object>::MaybeType Object::ToPrimitive(
    Isolate* isolate, HandleType<T> input, ToPrimitiveHint hint) {
  if (IsPrimitive(*input)) return input;
  return JSReceiver::ToPrimitive(isolate, Cast<JSReceiver>(input), hint);
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
typename HandleType<Number>::MaybeType Object::ToNumber(Isolate* isolate,
                                                        HandleType<T> input) {
  if (IsNumber(*input)) return Cast<Number>(input);  // Shortcut.
  return ConvertToNumber(isolate, Cast<Object>(input));
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
typename HandleType<Object>::MaybeType Object::ToNumeric(Isolate* isolate,
                                                         HandleType<T> input) {
  if (IsNumber(*input) || IsBigInt(*input)) return input;  // Shortcut.
  return ConvertToNumeric(isolate, Cast<Object>(input));
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
typename HandleType<Number>::MaybeType Object::ToInteger(Isolate* isolate,
                                                         HandleType<T> input) {
  if (IsSmi(*input)) return Cast<Smi>(input);
  return ConvertToInteger(isolate, Cast<Object>(input));
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
typename HandleType<Number>::MaybeType Object::ToInt32(Isolate* isolate,
                                                       HandleType<T> input) {
  if (IsSmi(*input)) return Cast<Smi>(input);
  return ConvertToInt32(isolate, Cast<Object>(input));
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
typename HandleType<Number>::MaybeType Object::ToUint32(Isolate* isolate,
                                                        HandleType<T> input) {
  if (IsSmi(*input)) {
    return typename HandleType<Number>::MaybeType(
        Smi::ToUint32Smi(Cast<Smi>(*input)), isolate);
  }
  return ConvertToUint32(isolate, Cast<Object>(input));
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
typename HandleType<String>::MaybeType Object::ToString(Isolate* isolate,
                                                        HandleType<T> input) {
  if (IsString(*input)) return Cast<String>(input);
  return ConvertToString(isolate, Cast<Object>(input));
}

// static
MaybeHandle<Object> Object::ToLength(Isolate* isolate,
                                     DirectHandle<Object> input) {
  if (IsSmi(*input)) {
    int value = std::max(Smi::ToInt(*input), 0);
    return handle(Smi::FromInt(value), isolate);
  }
  return ConvertToLength(isolate, input);
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
typename HandleType<Object>::MaybeType Object::ToIndex(
    Isolate* isolate, HandleType<T> input, MessageTemplate error_index) {
  if (IsSmi(*input) && Smi::ToInt(*input) >= 0) return input;
  return ConvertToIndex(isolate, Cast<Object>(input), error_index);
}


// static
template <typename ObjectType>
JSDispatchHandle HeapObject::AllocateAndInstallJSDispatchHandle(
    DirectHandle<ObjectType> host, size_t offset, Isolate* isolate,
    uint16_t parameter_count, DirectHandle<Code> code, WriteBarrierMode mode) {
  JSDispatchTable::Space* space =
      isolate->GetJSDispatchTableSpaceFor(host->field_address(offset));
  JSDispatchHandle handle =
      isolate->factory()->NewJSDispatchHandle(parameter_count, code, space);

  // Use a Release_Store to ensure that the store of the pointer into the table
  // is not reordered after the store of the handle. Otherwise, other threads
  // may access an uninitialized table entry and crash.
  auto location =
      reinterpret_cast<JSDispatchHandle*>(host->field_address(offset));
  base::AsAtomic32::Release_Store(location, handle);
  CONDITIONAL_JS_DISPATCH_HANDLE_WRITE_BARRIER(*host, handle, mode);

  return handle;
}

#ifdef VERIFY_HEAP
void HeapObject::VerifyObjectField(Isolate* isolate, int offset) {
  Object::VerifyPointer(isolate, TaggedField<Object>::load(this, offset));
  static_assert(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size);
}

void HeapObject::VerifyMaybeObjectField(Isolate* isolate, int offset) {
  Object::VerifyMaybeObjectPointer(
      isolate, TaggedField<MaybeObject>::load(this, offset));
  static_assert(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size);
}

void HeapObject::VerifySmiField(int offset) {
  CHECK(IsSmi(TaggedField<Object>::load(this, offset)));
  static_assert(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size);
}

#endif

// static
bool JSArray::MayHaveReadOnlyLength(Tagged<Map> js_array_map) {
  DCHECK(IsJSArrayMap(js_array_map));
  if (V8_UNLIKELY(
          js_array_map->instance_descriptors()->number_of_descriptors() == 0)) {
    return true;
  }
  DCHECK(!js_array_map->is_dictionary_map());

  // Fast path: "length" is the first fast property of arrays with non
  // dictionary properties. Since it's not configurable, it's guaranteed to be
  // the first in the descriptor array.
  InternalIndex first(0);
  DCHECK(js_array_map->instance_descriptors()->GetKey(first) ==
         GetReadOnlyRoots().length_string());
  return V8_UNLIKELY(
      js_array_map->instance_descriptors()->GetDetails(first).IsReadOnly());
}

bool JSArray::HasReadOnlyLength(DirectHandle<JSArray> array) {
  Tagged<Map> map = array->map();

  // If map guarantees that there can't be a read-only length, we are done.
  if (!MayHaveReadOnlyLength(map)) return false;
  return V8_UNLIKELY(HasReadOnlyLengthSlowPath(array));
}


inline bool IsSpecialReceiverInstanceType(InstanceType instance_type) {
  return instance_type <= LAST_SPECIAL_RECEIVER_TYPE;
}

// This should be in objects/map-inl.h, but can't, because of a cyclic
// dependency.
bool IsSpecialReceiverMap(Tagged<Map> map) {
  bool result = IsSpecialReceiverInstanceType(map->instance_type());
  DCHECK_IMPLIES(
      !result, !map->has_named_interceptor() && !map->is_access_check_needed());
  return result;
}

inline bool IsCustomElementsReceiverInstanceType(InstanceType instance_type) {
  return instance_type <= LAST_CUSTOM_ELEMENTS_RECEIVER;
}

// This should be in objects/map-inl.h, but can't, because of a cyclic
// dependency.
bool IsCustomElementsReceiverMap(Tagged<Map> map) {
  return IsCustomElementsReceiverInstanceType(map->instance_type());
}

WriteBarrierModeScope HeapObject::GetWriteBarrierMode(
    const DisallowGarbageCollection& promise) {
  return WriteBarrier::GetWriteBarrierModeForObject(this, promise);
}

// static
AllocationAlignment HeapObject::RequiredAlignment(AllocationSpace space,
                                                  Tagged<Map> map) {
  return RequiredAlignment(InSharedSpace{IsAnyWritableSharedSpace(space)}, map);
}

// static
AllocationAlignment HeapObject::RequiredAlignment(InSharedSpace in_shared_space,
                                                  Tagged<Map> map) {
  // TODO(v8:4153): We should think about requiring double alignment
  // in general for ByteArray, since they are used as backing store for typed
  // arrays now.
  // TODO(ishell, v8:8875): Consider using aligned allocations for BigInt.
  if (USE_ALLOCATION_ALIGNMENT_HEAP_NUMBER_BOOL) {
    int instance_type = map->instance_type();

    static_assert(!USE_ALLOCATION_ALIGNMENT_HEAP_NUMBER_BOOL ||
                  (OFFSET_OF_DATA_START(FixedDoubleArray) &
                   kDoubleAlignmentMask) == kTaggedSize);
    if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) return kDoubleAligned;

    static_assert(!USE_ALLOCATION_ALIGNMENT_HEAP_NUMBER_BOOL ||
                  (offsetof(HeapNumber, value_) & kDoubleAlignmentMask) ==
                      kTaggedSize);
    if (instance_type == HEAP_NUMBER_TYPE) return kDoubleUnaligned;
  }
#if V8_ENABLE_WEBASSEMBLY
  if (in_shared_space && v8_flags.wasm_shared) [[unlikely]] {
    int instance_type = map->instance_type();
    if (instance_type == WASM_STRUCT_TYPE ||
        instance_type == WASM_CUSTOM_MAP_TYPE) {
      // The map of a shared wasm struct needs to be in the shared space.
      DCHECK(HeapLayout::InWritableSharedSpace(map));
      return kDoubleAligned;
    } else if (instance_type == WASM_ARRAY_TYPE) {
      // The map of a shared wasm array needs to be in the shared space.
      DCHECK(HeapLayout::InWritableSharedSpace(map));
      return kDoubleUnaligned;
    }
  }
#endif
  return kTaggedAligned;
}

Address HeapObject::GetFieldAddress(int field_offset) const {
  return field_address(field_offset);
}

// static
Maybe<bool> Object::GreaterThan(Isolate* isolate, DirectHandle<Object> x,
                                DirectHandle<Object> y) {
  Maybe<ComparisonResult> result = Compare(isolate, x, y);
  if (result.IsJust()) {
    switch (result.FromJust()) {
      case ComparisonResult::kGreaterThan:
        return Just(true);
      case ComparisonResult::kLessThan:
      case ComparisonResult::kEqual:
      case ComparisonResult::kUndefined:
        return Just(false);
    }
  }
  return Nothing<bool>();
}

// static
Maybe<bool> Object::GreaterThanOrEqual(Isolate* isolate, DirectHandle<Object> x,
                                       DirectHandle<Object> y) {
  Maybe<ComparisonResult> result = Compare(isolate, x, y);
  if (result.IsJust()) {
    switch (result.FromJust()) {
      case ComparisonResult::kEqual:
      case ComparisonResult::kGreaterThan:
        return Just(true);
      case ComparisonResult::kLessThan:
      case ComparisonResult::kUndefined:
        return Just(false);
    }
  }
  return Nothing<bool>();
}

// static
Maybe<bool> Object::LessThan(Isolate* isolate, DirectHandle<Object> x,
                             DirectHandle<Object> y) {
  Maybe<ComparisonResult> result = Compare(isolate, x, y);
  if (result.IsJust()) {
    switch (result.FromJust()) {
      case ComparisonResult::kLessThan:
        return Just(true);
      case ComparisonResult::kEqual:
      case ComparisonResult::kGreaterThan:
      case ComparisonResult::kUndefined:
        return Just(false);
    }
  }
  return Nothing<bool>();
}

// static
Maybe<bool> Object::LessThanOrEqual(Isolate* isolate, DirectHandle<Object> x,
                                    DirectHandle<Object> y) {
  Maybe<ComparisonResult> result = Compare(isolate, x, y);
  if (result.IsJust()) {
    switch (result.FromJust()) {
      case ComparisonResult::kEqual:
      case ComparisonResult::kLessThan:
        return Just(true);
      case ComparisonResult::kGreaterThan:
      case ComparisonResult::kUndefined:
        return Just(false);
    }
  }
  return Nothing<bool>();
}

// static
Tagged<Object> Object::GetSimpleHash(Tagged<Object> object) {
  DisallowGarbageCollection no_gc;
  if (IsSmi(object)) {
    return Smi::FromInt(SmiHash32(static_cast<uint32_t>(Smi::ToInt(object))));
  }
  auto instance_type = Cast<HeapObject>(object)->map()->instance_type();
  if (InstanceTypeChecker::IsHeapNumber(instance_type)) {
    double num = Cast<HeapNumber>(object)->value();
    if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
    // For values in Signed32 range, including -0 (which is considered equal
    // to 0 because collections use SameValueZero), hash the integer form to
    // match the Smi branch above.
    uint32_t hash;
    // Check range before conversion to avoid undefined behavior.
    if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) {
      hash = SmiHash32(static_cast<uint32_t>(FastD2I(num)));
    } else {
      hash = SmiHash64(base::double_to_uint64(num));
    }
    return Smi::FromInt(hash);
  } else if (InstanceTypeChecker::IsName(instance_type)) {
    uint32_t hash = Cast<Name>(object)->EnsureHash();
    return Smi::FromInt(hash);
  } else if (InstanceTypeChecker::IsOddball(instance_type)) {
    uint32_t hash = Cast<Oddball>(object)->to_string()->EnsureHash();
    return Smi::FromInt(hash);
  } else if (InstanceTypeChecker::IsBigInt(instance_type)) {
    uint32_t hash = Cast<BigInt>(object)->Hash();
    return Smi::FromInt(hash & Smi::kMaxValue);
  } else if (InstanceTypeChecker::IsSharedFunctionInfo(instance_type)) {
    uint32_t hash = Cast<SharedFunctionInfo>(object)->Hash();
    return Smi::FromInt(hash & Smi::kMaxValue);
  } else if (InstanceTypeChecker::IsScopeInfo(instance_type)) {
    uint32_t hash = Cast<ScopeInfo>(object)->Hash();
    return Smi::FromInt(hash & Smi::kMaxValue);
  } else if (InstanceTypeChecker::IsScript(instance_type)) {
    int id = Cast<Script>(object)->id();
    return Smi::FromInt(SmiHash32(static_cast<uint32_t>(id)));
  } else if (InstanceTypeChecker::IsTemplateInfo(instance_type)) {
    uint32_t hash = Cast<TemplateInfo>(object)->GetHash();
    DCHECK_EQ(hash, hash & kSmiHashMask);
    return Smi::FromInt(hash);
  }

  DCHECK_NE(instance_type, HOLE_TYPE);
  DCHECK(IsJSReceiver(object));
  return object;
}

// static
Tagged<Object> Object::GetHash(Tagged<Object> obj) {
  DisallowGarbageCollection no_gc;
  Tagged<Object> hash = GetSimpleHash(obj);
  if (IsSmi(hash)) return hash;

  // Make sure that we never cast internal objects to JSReceivers.
  CHECK(IsJSReceiver(obj));
  Tagged<JSReceiver> receiver = Cast<JSReceiver>(obj);
  return receiver->GetIdentityHash();
}

// static
template <typename T, template <typename> typename HandleType>
  requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
typename HandleType<Object>::MaybeType Object::Share(
    Isolate* isolate, HandleType<T> value,
    ShouldThrow throw_if_cannot_be_shared) {
  // Sharing values requires the RO space be shared.
  if (IsShared(*value)) return value;
  return ShareSlow(isolate, Cast<HeapObject>(value), throw_if_cannot_be_shared);
}

// https://tc39.es/ecma262/#sec-canbeheldweakly
// static
bool Object::CanBeHeldWeakly(Tagged<Object> obj) {
  if (IsJSReceiver(obj)) {
    // TODO(v8:12547) Shared structs and arrays should only be able to point
    // to shared values in weak collections. For now, disallow them as weak
    // collection keys.
#if V8_ENABLE_WEBASSEMBLY
    if (v8_flags.wasm_shared &&
        (IsWasmStruct(obj) || IsWasmCustomMap(obj) || IsWasmArray(obj)) &&
        HeapLayout::InAnySharedSpace(Cast<HeapObject>(obj))) {
      return false;
    }
#endif
    return (!v8_flags.harmony_struct ||
            (!IsJSSharedStruct(obj) && !IsJSSharedArray(obj)));
  }
  return IsSymbol(obj) && !Cast<Symbol>(obj)->is_in_public_symbol_table();
}

DirectHandle<Object> ObjectHashTableShapeBase::AsHandle(
    DirectHandle<Object> key) {
  return key;
}

Relocatable::Relocatable(Isolate* isolate) {
  isolate_ = isolate;
  prev_ = isolate->relocatable_top();
  isolate->set_relocatable_top(this);
}

Relocatable::~Relocatable() {
  DCHECK_EQ(isolate_->relocatable_top(), this);
  isolate_->set_relocatable_top(prev_);
}

// Predictably converts HeapObject or Address to uint32 by calculating
// offset of the address in respective MemoryChunk.
inline uint32_t ObjectAddressForHashing(Address object) {
  return MemoryChunk::AddressToOffset(object);
}

inline DirectHandle<Object> MakeEntryPair(Isolate* isolate, size_t index,
                                          DirectHandle<Object> value) {
  DirectHandle<Object> key = isolate->factory()->SizeToString(index);
  DirectHandle<FixedArray> entry_storage = isolate->factory()->NewFixedArray(2);
  {
    entry_storage->set(0, *key, SKIP_WRITE_BARRIER);
    entry_storage->set(1, *value, SKIP_WRITE_BARRIER);
  }
  return isolate->factory()->NewJSArrayWithElements(entry_storage,
                                                    PACKED_ELEMENTS, 2);
}

inline DirectHandle<Object> MakeEntryPair(Isolate* isolate,
                                          DirectHandle<Object> key,
                                          DirectHandle<Object> value) {
  DirectHandle<FixedArray> entry_storage = isolate->factory()->NewFixedArray(2);
  {
    entry_storage->set(0, *key, SKIP_WRITE_BARRIER);
    entry_storage->set(1, *value, SKIP_WRITE_BARRIER);
  }
  return isolate->factory()->NewJSArrayWithElements(entry_storage,
                                                    PACKED_ELEMENTS, 2);
}

}  // namespace internal
}  // namespace v8

#include "src/objects/object-macros-undef.h"

#endif  // V8_OBJECTS_OBJECTS_INL_H_