blob: d77f5622b8389a451a4572a4a4991018611234ab [file]
// 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_