| // Copyright 2015 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_H_ |
| #define V8_OBJECTS_OBJECTS_H_ |
| |
| #include <iosfwd> |
| #include <memory> |
| |
| #include "include/v8-internal.h" |
| #include "include/v8config.h" |
| #include "src/base/bits.h" |
| #include "src/base/build_config.h" |
| #include "src/base/flags.h" |
| #include "src/base/logging.h" |
| #include "src/base/memory.h" |
| #include "src/base/sanitizer/tsan.h" |
| #include "src/codegen/constants-arch.h" |
| #include "src/common/assert-scope.h" |
| #include "src/common/checks.h" |
| #include "src/common/message-template.h" |
| #include "src/common/operation.h" |
| #include "src/common/ptr-compr.h" |
| #include "src/flags/flags.h" |
| #include "src/objects/elements-kind.h" |
| #include "src/objects/field-index.h" |
| #include "src/objects/map-word.h" |
| #include "src/objects/object-list-macros.h" |
| #include "src/objects/object-predicates.h" |
| #include "src/objects/objects-definitions.h" |
| #include "src/objects/property-details.h" |
| #include "src/objects/tagged-impl.h" |
| #include "src/objects/tagged.h" |
| #include "src/utils/utils.h" |
| |
| // Has to be the last include (doesn't have include guards): |
| #include "src/objects/object-macros.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| struct InliningPosition; |
| class LookupIterator; |
| class PropertyDescriptorObject; |
| class ReadOnlyRoots; |
| class EarlyReadOnlyRoots; |
| class RootVisitor; |
| class PropertyKey; |
| |
| enum WriteBarrierMode { |
| // Skips write barrier. Used for static write barrier removal. Usually used |
| // for avoiding write barriers on newly allocated objects. This is verified |
| // using WriteBarrier::IsRequired. |
| SKIP_WRITE_BARRIER, |
| // Skips the write barrier but is used for runtime write barrier removal. Only |
| // use this through GetWriteBarrierMode() which checks at runtime whether the |
| // object resides in the young generation. This allows to remove barriers in |
| // scenarios where static write barrier removal wouldn't be allowed. |
| SKIP_WRITE_BARRIER_SCOPE, |
| // Skips the write barrier during GC atomic pause. The GC uses explicit |
| // barriers where needed. |
| SKIP_WRITE_BARRIER_FOR_GC, |
| // Skips the write barrier in CSA/Turbofan. Used to skip Turbofan's |
| // verification in the MemoryOptimizer. |
| UNSAFE_SKIP_WRITE_BARRIER, |
| // Performs the special ephemeron key write barrier. |
| UPDATE_EPHEMERON_KEY_WRITE_BARRIER, |
| // Performs regular write barrier. |
| UPDATE_WRITE_BARRIER |
| }; |
| |
| // PropertyNormalizationMode is used to specify whether to keep |
| // inobject properties when normalizing properties of a JSObject. |
| enum PropertyNormalizationMode { |
| CLEAR_INOBJECT_PROPERTIES, |
| KEEP_INOBJECT_PROPERTIES |
| }; |
| |
| // Indicates whether transitions can be added to a source map or not. |
| enum TransitionFlag { INSERT_TRANSITION, OMIT_TRANSITION }; |
| |
| // Indicates the kind of transition: the target map of the transition |
| // either extends the current map with a new property, or it modifies the |
| // property that was added last to the current map. Otherwise, it can |
| // be a prototype transition, or anything else. |
| enum TransitionKindFlag { |
| SIMPLE_PROPERTY_TRANSITION, |
| PROPERTY_TRANSITION, |
| PROTOTYPE_TRANSITION, |
| SPECIAL_TRANSITION |
| }; |
| |
| // Indicates whether we are only interested in the descriptors of a particular |
| // map, or in all descriptors in the descriptor array. |
| enum DescriptorFlag { ALL_DESCRIPTORS, OWN_DESCRIPTORS }; |
| |
| // Instance size sentinel for objects of variable size. |
| const int kVariableSizeSentinel = 0; |
| |
| // We may store the unsigned bit field as signed Smi value and do not |
| // use the sign bit. |
| const int kStubMajorKeyBits = 8; |
| const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1; |
| |
| // Result of an abstract relational comparison of x and y, implemented according |
| // to ES6 section 7.2.11 Abstract Relational Comparison. |
| enum class ComparisonResult { |
| kLessThan = -1, // x < y |
| kEqual = 0, // x = y |
| kGreaterThan = 1, // x > y |
| kUndefined = 2 // at least one of x or y was undefined or NaN |
| }; |
| |
| // (Returns false whenever {result} is kUndefined.) |
| bool ComparisonResultToBool(Operation op, ComparisonResult result); |
| |
| enum class OnNonExistent { kThrowReferenceError, kReturnUndefined }; |
| |
| // The element types selection for CreateListFromArrayLike. |
| enum class ElementTypes { kAll, kStringAndSymbol }; |
| |
| // Currently DefineOwnPropertyIgnoreAttributes invokes the setter |
| // interceptor and user-defined setters during define operations, |
| // even in places where it makes more sense to invoke the definer |
| // interceptor and not invoke the setter: e.g. both the definer and |
| // the setter interceptors are called in Object.defineProperty(). |
| // kDefine allows us to implement the define semantics correctly |
| // in selected locations. |
| // TODO(joyee): see if we can deprecate the old behavior. |
| enum class EnforceDefineSemantics { kSet, kDefine }; |
| |
| // TODO(mythria): Move this to a better place. |
| ShouldThrow GetShouldThrow(Isolate* isolate, Maybe<ShouldThrow> should_throw); |
| |
| // Object is the abstract superclass for all classes in the |
| // object hierarchy. |
| // Object does not use any virtual functions to avoid the |
| // allocation of the C++ vtable. |
| // There must only be a single data member in Object: the Address ptr, |
| // containing the tagged heap pointer that this Object instance refers to. |
| // For a design overview, see: |
| // https://docs.google.com/document/d/1_w49sakC1XM1OptjTurBDqO86NE16FH8LwbeUAtrbCo |
| class Object : public AllStatic { |
| public: |
| enum class Conversion { |
| kToNumber, // Number = Smi or HeapNumber |
| kToNumeric // Numeric = Smi or HeapNumber or BigInt |
| }; |
| |
| // https://tc39.es/ecma262/#sec-isarray. NOT to be confused with %_IsArray. |
| V8_INLINE |
| V8_WARN_UNUSED_RESULT static Maybe<bool> IsArray(DirectHandle<Object> object); |
| |
| // Extract the double value of a Number (Smi or HeapNumber). |
| static inline double NumberValue(Tagged<Number> obj); |
| static inline double NumberValue(Tagged<Object> obj); |
| static inline double NumberValue(Tagged<HeapNumber> obj); |
| static inline double NumberValue(Tagged<Smi> obj); |
| V8_EXPORT_PRIVATE static bool ToInt32(Tagged<Object> obj, int32_t* value); |
| static inline bool ToUint32(Tagged<Object> obj, uint32_t* value); |
| |
| // ES6 section 7.1.5 ToIntegerOrInfinity |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| V8_WARN_UNUSED_RESULT static inline Maybe<double> IntegerValue( |
| Isolate* isolate, HandleType<T> input); |
| |
| // Selects optimal representation and constness for a given value. |
| // Usually, the constness stays unmodified unless the value is a HeapNumber |
| // with the hole NaN pattern. This is necessary to distinguish between |
| // initialized and non-initialized double fields. |
| static inline std::pair<Representation, PropertyConstness> |
| OptimalRepresentation(Tagged<Object> obj, PropertyConstness constness); |
| |
| static inline ElementsKind OptimalElementsKind(Tagged<Object> obj); |
| |
| // If {allow_coercion} is true, then a Smi will be considered to fit |
| // a Double representation, since it can be converted to a HeapNumber |
| // and stored. |
| static inline bool FitsRepresentation(Tagged<Object> obj, |
| Representation representation, |
| bool allow_coercion = true); |
| |
| static inline bool FilterKey(Tagged<Object> obj, PropertyFilter filter); |
| |
| static DirectHandle<FieldType> OptimalType(Tagged<Object> obj, |
| Isolate* isolate, |
| Representation representation); |
| |
| V8_EXPORT_PRIVATE static Handle<UnionOf<JSAny, Hole>> NewStorageFor( |
| Isolate* isolate, Handle<UnionOf<JSAny, Hole>> object, |
| Representation representation); |
| |
| template <AllocationType allocation_type = AllocationType::kYoung, |
| typename IsolateT> |
| static Handle<JSAny> WrapForRead(IsolateT* isolate, Handle<JSAny> object, |
| Representation representation); |
| |
| // Returns true if the object is of the correct type to be used as an |
| // implementation of a JSObject's elements. |
| static inline bool HasValidElements(Tagged<Object> obj); |
| |
| // ECMA-262 9.2. |
| template <typename IsolateT> |
| V8_EXPORT_PRIVATE static bool BooleanValue(Tagged<Object> obj, |
| IsolateT* isolate); |
| static Tagged<Object> ToBoolean(Tagged<Object> obj, Isolate* isolate); |
| |
| // ES6 section 7.2.11 Abstract Relational Comparison |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<ComparisonResult> |
| Compare(Isolate* isolate, DirectHandle<Object> x, DirectHandle<Object> y); |
| |
| // ES6 section 7.2.12 Abstract Equality Comparison |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<bool> Equals( |
| Isolate* isolate, DirectHandle<Object> x, DirectHandle<Object> y); |
| |
| // ES6 section 7.2.13 Strict Equality Comparison |
| V8_EXPORT_PRIVATE static bool StrictEquals(Tagged<Object> obj, |
| Tagged<Object> that); |
| |
| // TODO(b/42203211): ToObject, ToString and other conversion methods are |
| // templatized by the handle type and by the object type, so that passing a |
| // Handle<T> is not ambiguous when T is a subtype of Object (it could be |
| // implicitly converted both to Handle<Object> and to DirectHandle<Object>). |
| // Here, T should be a subtype of Object, which is enforced by the last |
| // template argument and the similar restriction on Handle's constructor. When |
| // the migration to DirectHandle is complete, these functions can again accept |
| // simply a DirectHandle<Object>. |
| |
| // ES6 section 7.1.13 ToObject |
| // Convert to a JSObject if needed. |
| // native_context is used when creating wrapper object. |
| // |
| // Passing a non-null method_name allows us to give a more informative |
| // error message for those cases where ToObject is being called on |
| // the receiver of a built-in method. |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| V8_WARN_UNUSED_RESULT static inline typename HandleType<JSReceiver>::MaybeType |
| ToObject(Isolate* isolate, HandleType<T> object, |
| const char* method_name = nullptr); |
| V8_WARN_UNUSED_RESULT static MaybeHandle<JSReceiver> ToObjectImpl( |
| Isolate* isolate, DirectHandle<Object> object, |
| const char* method_name = nullptr); |
| |
| // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee. |
| V8_WARN_UNUSED_RESULT static MaybeDirectHandle<JSReceiver> ConvertReceiver( |
| Isolate* isolate, DirectHandle<Object> object); |
| |
| // ES6 section 7.1.14 ToPropertyKey |
| template <template <typename> typename HandleType> |
| V8_WARN_UNUSED_RESULT static inline typename HandleType<Name>::MaybeType |
| ToName(Isolate* isolate, HandleType<Object> input) |
| requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>); |
| |
| // ES6 section 7.1.1 ToPrimitive |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| V8_WARN_UNUSED_RESULT static inline typename HandleType<Object>::MaybeType |
| ToPrimitive(Isolate* isolate, HandleType<T> input, |
| ToPrimitiveHint hint = ToPrimitiveHint::kDefault); |
| |
| // ES6 section 7.1.3 ToNumber |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| V8_WARN_UNUSED_RESULT static inline typename HandleType<Number>::MaybeType |
| ToNumber(Isolate* isolate, HandleType<T> input); |
| |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| V8_WARN_UNUSED_RESULT static inline typename HandleType<Object>::MaybeType |
| ToNumeric(Isolate* isolate, HandleType<T> input); |
| |
| // ES6 section 7.1.4 ToInteger |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| V8_WARN_UNUSED_RESULT static inline typename HandleType<Number>::MaybeType |
| ToInteger(Isolate* isolate, HandleType<T> input); |
| |
| // ES6 section 7.1.5 ToInt32 |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| V8_WARN_UNUSED_RESULT static inline typename HandleType<Number>::MaybeType |
| ToInt32(Isolate* isolate, HandleType<T> input); |
| |
| // ES6 section 7.1.6 ToUint32 |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| V8_WARN_UNUSED_RESULT static inline typename HandleType<Number>::MaybeType |
| ToUint32(Isolate* isolate, HandleType<T> input); |
| |
| // ES6 section 7.1.12 ToString |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| V8_WARN_UNUSED_RESULT static inline typename HandleType<String>::MaybeType |
| ToString(Isolate* isolate, HandleType<T> input); |
| |
| V8_EXPORT_PRIVATE static MaybeDirectHandle<String> NoSideEffectsToMaybeString( |
| Isolate* isolate, DirectHandle<Object> input); |
| |
| V8_EXPORT_PRIVATE static DirectHandle<String> NoSideEffectsToString( |
| Isolate* isolate, DirectHandle<Object> input); |
| |
| // ES6 section 7.1.14 ToPropertyKey |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| V8_WARN_UNUSED_RESULT static inline typename HandleType<Object>::MaybeType |
| ToPropertyKey(Isolate* isolate, HandleType<T> value); |
| |
| // ES6 section 7.1.15 ToLength |
| V8_WARN_UNUSED_RESULT static inline MaybeHandle<Object> ToLength( |
| Isolate* isolate, DirectHandle<Object> input); |
| |
| // ES6 section 7.1.17 ToIndex |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| V8_WARN_UNUSED_RESULT static inline typename HandleType<Object>::MaybeType |
| ToIndex(Isolate* isolate, HandleType<T> input, MessageTemplate error_index); |
| |
| // ES6 section 7.3.9 GetMethod |
| V8_WARN_UNUSED_RESULT static MaybeDirectHandle<Object> GetMethod( |
| Isolate* isolate, DirectHandle<JSReceiver> receiver, |
| DirectHandle<Name> name); |
| |
| // ES6 section 7.3.17 CreateListFromArrayLike |
| V8_WARN_UNUSED_RESULT static MaybeDirectHandle<FixedArray> |
| CreateListFromArrayLike(Isolate* isolate, DirectHandle<Object> object, |
| ElementTypes element_types); |
| |
| // Get length property and apply ToLength. |
| V8_WARN_UNUSED_RESULT static MaybeDirectHandle<Object> GetLengthFromArrayLike( |
| Isolate* isolate, DirectHandle<JSReceiver> object); |
| |
| // ES6 section 12.5.6 The typeof Operator |
| static Handle<String> TypeOf(Isolate* isolate, DirectHandle<Object> object); |
| |
| // ES6 section 12.7 Additive Operators |
| V8_WARN_UNUSED_RESULT static MaybeDirectHandle<Object> Add( |
| Isolate* isolate, Handle<Object> lhs, Handle<Object> rhs); |
| |
| // ES6 section 12.9 Relational Operators |
| V8_WARN_UNUSED_RESULT static inline Maybe<bool> GreaterThan( |
| Isolate* isolate, DirectHandle<Object> x, DirectHandle<Object> y); |
| V8_WARN_UNUSED_RESULT static inline Maybe<bool> GreaterThanOrEqual( |
| Isolate* isolate, DirectHandle<Object> x, DirectHandle<Object> y); |
| V8_WARN_UNUSED_RESULT static inline Maybe<bool> LessThan( |
| Isolate* isolate, DirectHandle<Object> x, DirectHandle<Object> y); |
| V8_WARN_UNUSED_RESULT static inline Maybe<bool> LessThanOrEqual( |
| Isolate* isolate, DirectHandle<Object> x, DirectHandle<Object> y); |
| |
| // ES6 section 7.3.19 OrdinaryHasInstance (C, O). |
| V8_WARN_UNUSED_RESULT static MaybeHandle<Object> OrdinaryHasInstance( |
| Isolate* isolate, DirectHandle<JSAny> callable, |
| DirectHandle<JSAny> object); |
| |
| // ES6 section 12.10.4 Runtime Semantics: InstanceofOperator(O, C) |
| V8_WARN_UNUSED_RESULT static MaybeHandle<Object> InstanceOf( |
| Isolate* isolate, DirectHandle<JSAny> object, |
| DirectHandle<JSAny> callable); |
| |
| static MaybeHandle<Object> InstantiateIfLazyClosure( |
| LookupIterator* it, DirectHandle<Object> value); |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static MaybeHandle<Object> |
| GetProperty(LookupIterator* it, bool is_global_reference = false); |
| |
| // ES6 [[Set]] (when passed kDontThrow) |
| // Invariants for this and related functions (unless stated otherwise): |
| // 1) When the result is Nothing, an exception is pending. |
| // 2) When passed kThrowOnError, the result is never Just(false). |
| // In some cases, an exception is thrown regardless of the ShouldThrow |
| // argument. These cases are either in accordance with the spec or not |
| // covered by it (eg., concerning API callbacks). |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<bool> SetProperty( |
| LookupIterator* it, DirectHandle<Object> value, StoreOrigin store_origin, |
| Maybe<ShouldThrow> should_throw = Nothing<ShouldThrow>()); |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static MaybeHandle<Object> |
| SetProperty(Isolate* isolate, DirectHandle<JSAny> object, |
| DirectHandle<Name> name, DirectHandle<Object> value, |
| StoreOrigin store_origin = StoreOrigin::kMaybeKeyed, |
| Maybe<ShouldThrow> should_throw = Nothing<ShouldThrow>()); |
| V8_WARN_UNUSED_RESULT static inline MaybeDirectHandle<Object> |
| SetPropertyOrElement(Isolate* isolate, DirectHandle<JSAny> object, |
| DirectHandle<Name> name, DirectHandle<Object> value, |
| Maybe<ShouldThrow> should_throw = Nothing<ShouldThrow>(), |
| StoreOrigin store_origin = StoreOrigin::kMaybeKeyed); |
| V8_WARN_UNUSED_RESULT static inline MaybeDirectHandle<Object> |
| SetPropertyOrElement(Isolate* isolate, DirectHandle<JSAny> object, |
| PropertyKey key, DirectHandle<Object> value, |
| Maybe<ShouldThrow> should_throw = Nothing<ShouldThrow>(), |
| StoreOrigin store_origin = StoreOrigin::kMaybeKeyed); |
| |
| V8_WARN_UNUSED_RESULT static Maybe<bool> SetSuperProperty( |
| LookupIterator* it, DirectHandle<Object> value, StoreOrigin store_origin, |
| Maybe<ShouldThrow> should_throw = Nothing<ShouldThrow>()); |
| |
| V8_WARN_UNUSED_RESULT static Maybe<bool> CannotCreateProperty( |
| Isolate* isolate, DirectHandle<JSAny> receiver, DirectHandle<Object> name, |
| Maybe<ShouldThrow> should_throw); |
| V8_WARN_UNUSED_RESULT static Maybe<bool> WriteToReadOnlyProperty( |
| LookupIterator* it, DirectHandle<Object> value, |
| Maybe<ShouldThrow> should_throw); |
| V8_WARN_UNUSED_RESULT static Maybe<bool> WriteToReadOnlyProperty( |
| Isolate* isolate, DirectHandle<JSAny> receiver, DirectHandle<Object> name, |
| DirectHandle<Object> value, ShouldThrow should_throw); |
| V8_WARN_UNUSED_RESULT static Maybe<bool> RedefineIncompatibleProperty( |
| Isolate* isolate, DirectHandle<Object> name, DirectHandle<Object> value, |
| Maybe<ShouldThrow> should_throw); |
| V8_WARN_UNUSED_RESULT static Maybe<bool> SetDataProperty( |
| LookupIterator* it, DirectHandle<Object> value); |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<bool> AddDataProperty( |
| LookupIterator* it, DirectHandle<Object> value, |
| PropertyAttributes attributes, Maybe<ShouldThrow> should_throw, |
| StoreOrigin store_origin, |
| EnforceDefineSemantics semantics = EnforceDefineSemantics::kSet); |
| |
| V8_WARN_UNUSED_RESULT static Maybe<bool> TransitionAndWriteDataProperty( |
| LookupIterator* it, DirectHandle<Object> value, |
| PropertyAttributes attributes, Maybe<ShouldThrow> should_throw, |
| StoreOrigin store_origin); |
| |
| V8_WARN_UNUSED_RESULT static inline MaybeHandle<Object> GetPropertyOrElement( |
| Isolate* isolate, DirectHandle<JSAny> object, DirectHandle<Name> name); |
| V8_WARN_UNUSED_RESULT static inline MaybeHandle<Object> GetPropertyOrElement( |
| Isolate* isolate, DirectHandle<JSAny> object, PropertyKey key); |
| V8_WARN_UNUSED_RESULT static inline MaybeHandle<Object> GetProperty( |
| Isolate* isolate, DirectHandle<JSAny> object, DirectHandle<Name> name); |
| |
| V8_WARN_UNUSED_RESULT static MaybeHandle<JSAny> GetPropertyWithAccessor( |
| LookupIterator* it); |
| V8_WARN_UNUSED_RESULT static Maybe<bool> SetPropertyWithAccessor( |
| LookupIterator* it, DirectHandle<Object> value, |
| Maybe<ShouldThrow> should_throw); |
| |
| V8_WARN_UNUSED_RESULT static MaybeHandle<JSAny> GetPropertyWithDefinedGetter( |
| DirectHandle<JSAny> receiver, DirectHandle<JSReceiver> getter); |
| V8_WARN_UNUSED_RESULT static Maybe<bool> SetPropertyWithDefinedSetter( |
| DirectHandle<JSAny> receiver, DirectHandle<JSReceiver> setter, |
| DirectHandle<Object> value, Maybe<ShouldThrow> should_throw); |
| |
| V8_WARN_UNUSED_RESULT static inline MaybeHandle<Object> GetElement( |
| Isolate* isolate, DirectHandle<JSAny> object, uint32_t index); |
| |
| V8_WARN_UNUSED_RESULT static inline MaybeDirectHandle<Object> SetElement( |
| Isolate* isolate, DirectHandle<JSAny> object, uint32_t index, |
| DirectHandle<Object> value, ShouldThrow should_throw); |
| |
| // Returns the permanent hash code associated with this object. May return |
| // undefined if not yet created. |
| static inline Tagged<Object> GetHash(Tagged<Object> obj); |
| |
| // Returns the permanent hash code associated with this object depending on |
| // the actual object type. May create and store a hash code if needed and none |
| // exists. |
| V8_EXPORT_PRIVATE static Tagged<Smi> GetOrCreateHash(Tagged<Object> obj, |
| Isolate* isolate); |
| |
| // Checks whether this object has the same value as the given one. This |
| // function is implemented according to ES5, section 9.12 and can be used |
| // to implement the Object.is function. |
| V8_EXPORT_PRIVATE static bool SameValue(Tagged<Object> obj, |
| Tagged<Object> other); |
| |
| // A part of SameValue which handles Number vs. Number case. |
| // Treats NaN == NaN and +0 != -0. |
| inline static bool SameNumberValue(double number1, double number2); |
| |
| // Checks whether this object has the same value as the given one. |
| // +0 and -0 are treated equal. Everything else is the same as SameValue. |
| // This function is implemented according to ES6, section 7.2.4 and is used |
| // by ES6 Map and Set. |
| static bool SameValueZero(Tagged<Object> obj, Tagged<Object> other); |
| |
| // ES6 section 9.4.2.3 ArraySpeciesCreate (part of it) |
| V8_WARN_UNUSED_RESULT static MaybeDirectHandle<Object> |
| ArraySpeciesConstructor(Isolate* isolate, DirectHandle<JSAny> original_array); |
| |
| // ES6 section 7.3.20 SpeciesConstructor ( O, defaultConstructor ) |
| V8_WARN_UNUSED_RESULT static MaybeDirectHandle<Object> SpeciesConstructor( |
| Isolate* isolate, DirectHandle<JSReceiver> recv, |
| DirectHandle<JSFunction> default_ctor); |
| |
| // Tries to convert an object to an array length. Returns true and sets the |
| // output parameter if it succeeds. |
| static inline bool ToArrayLength(Tagged<Object> obj, uint32_t* index); |
| |
| // Tries to convert an object to an array index. Returns true and sets the |
| // output parameter if it succeeds. Equivalent to ToArrayLength, but does not |
| // allow kMaxUInt32. |
| static V8_WARN_UNUSED_RESULT inline bool ToArrayIndex(Tagged<Object> obj, |
| uint32_t* index); |
| |
| // Tries to convert an object to an index (in the range 0..size_t::max). |
| // Returns true and sets the output parameter if it succeeds. |
| static inline bool ToIntegerIndex(Tagged<Object> obj, size_t* index); |
| |
| // Returns true if the result of iterating over the object is the same |
| // (including observable effects) as simply accessing the properties between 0 |
| // and length. |
| V8_EXPORT_PRIVATE static bool IterationHasObservableEffects( |
| Tagged<Object> obj); |
| |
| // TC39 "Dynamic Code Brand Checks" |
| static bool IsCodeLike(Tagged<Object> obj, Isolate* isolate); |
| |
| EXPORT_DECL_STATIC_VERIFIER(Object) |
| |
| #ifdef VERIFY_HEAP |
| // Verify a pointer is a valid (non-InstructionStream) object pointer. |
| // When V8_EXTERNAL_CODE_SPACE is enabled InstructionStream objects are |
| // not allowed. |
| static void VerifyPointer(Isolate* isolate, Tagged<Object> p); |
| // Verify a pointer is a valid (non-InstructionStream) object pointer, |
| // potentially a weak one. |
| // When V8_EXTERNAL_CODE_SPACE is enabled InstructionStream objects are |
| // not allowed. |
| static void VerifyMaybeObjectPointer(Isolate* isolate, Tagged<MaybeObject> p); |
| // Verify a pointer is a valid object pointer. |
| // InstructionStream objects are allowed regardless of the |
| // V8_EXTERNAL_CODE_SPACE mode. |
| static void VerifyAnyTagged(Isolate* isolate, Tagged<Object> p); |
| #endif |
| |
| // Layout description. |
| static const int kHeaderSize = 0; // Object does not take up any space. |
| |
| // For use with std::unordered_set. |
| struct Hasher { |
| size_t operator()(const Tagged<Object> o) const { |
| return std::hash<v8::internal::Address>{}(static_cast<Tagged_t>(o.ptr())); |
| } |
| }; |
| |
| // For use with std::unordered_set/unordered_map when one of the objects may |
| // be located outside the main pointer compression cage, for example in |
| // trusted space. In this case, we must use full pointer comparison. |
| struct KeyEqualSafe { |
| bool operator()(const Tagged<Object> a, const Tagged<Object> b) const { |
| return a.SafeEquals(b); |
| } |
| }; |
| |
| // For use with std::map. |
| struct Comparer { |
| bool operator()(const Tagged<Object> a, const Tagged<Object> b) const { |
| return a < b; |
| } |
| }; |
| |
| // Same as above, but can be used when one of the objects may be located |
| // outside of the main pointer compression cage, for example in trusted |
| // space. In this case, we must use full pointer comparison. |
| struct FullPtrComparer { |
| bool operator()(const Tagged<Object> a, const Tagged<Object> b) const { |
| return a.ptr() < b.ptr(); |
| } |
| }; |
| |
| // If the receiver is the JSGlobalObject, the store was contextual. In case |
| // the property did not exist yet on the global object itself, we have to |
| // throw a reference error in strict mode. In sloppy mode, we continue. |
| // Returns false if the exception was thrown, otherwise true. |
| static bool CheckContextualStoreToJSGlobalObject( |
| LookupIterator* it, Maybe<ShouldThrow> should_throw); |
| |
| // Returns an equivalent value that's safe to share across Isolates if |
| // possible. Acts as the identity function when value->IsShared(). |
| template <typename T, template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) |
| static inline typename HandleType<Object>::MaybeType Share( |
| Isolate* isolate, HandleType<T> value, |
| ShouldThrow throw_if_cannot_be_shared); |
| |
| template <template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>) |
| static typename HandleType<Object>::MaybeType ShareSlow( |
| Isolate* isolate, HandleType<HeapObject> value, |
| ShouldThrow throw_if_cannot_be_shared); |
| |
| // Whether this Object can be held weakly, i.e. whether it can be used as a |
| // key in WeakMap, as a key in WeakSet, as the target of a WeakRef, or as a |
| // target or unregister token of a FinalizationRegistry. |
| static inline bool CanBeHeldWeakly(Tagged<Object> obj); |
| |
| private: |
| friend class CompressedObjectSlot; |
| friend class FullObjectSlot; |
| friend class LookupIterator; |
| friend class StringStream; |
| |
| // Return the map of the root of object's prototype chain. |
| static Tagged<Map> GetPrototypeChainRootMap(Tagged<Object> obj, |
| Isolate* isolate); |
| |
| // Returns a non-SMI for JSReceivers, but returns the hash code forp |
| // simple objects. This avoids a double lookup in the cases where |
| // we know we will add the hash to the JSReceiver if it does not |
| // already exist. |
| // |
| // Despite its size, this needs to be inlined for performance |
| // reasons. |
| static inline Tagged<Object> GetSimpleHash(Tagged<Object> object); |
| |
| // Helper for SetProperty and SetSuperProperty. |
| // Return value is only meaningful if [found] is set to true on return. |
| V8_WARN_UNUSED_RESULT static Maybe<bool> SetPropertyInternal( |
| LookupIterator* it, DirectHandle<Object> value, |
| Maybe<ShouldThrow> should_throw, StoreOrigin store_origin, bool* found); |
| |
| template <template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>) |
| V8_WARN_UNUSED_RESULT static typename HandleType<Name>::MaybeType |
| ConvertToName(Isolate* isolate, HandleType<Object> input); |
| template <template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>) |
| V8_WARN_UNUSED_RESULT static typename HandleType<Object>::MaybeType |
| ConvertToPropertyKey(Isolate* isolate, HandleType<Object> value); |
| template <template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>) |
| EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) V8_WARN_UNUSED_RESULT static |
| typename HandleType<String>::MaybeType |
| ConvertToString(Isolate* isolate, HandleType<Object> input); |
| template <template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>) |
| V8_WARN_UNUSED_RESULT static typename HandleType<Number>::MaybeType |
| ConvertToNumber(Isolate* isolate, HandleType<Object> input); |
| template <template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>) |
| V8_WARN_UNUSED_RESULT static typename HandleType<Numeric>::MaybeType |
| ConvertToNumeric(Isolate* isolate, HandleType<Object> input); |
| template <template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>) |
| EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) V8_WARN_UNUSED_RESULT static |
| typename HandleType<Number>::MaybeType |
| ConvertToInteger(Isolate* isolate, HandleType<Object> input); |
| template <template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>) |
| V8_WARN_UNUSED_RESULT static HandleType<Number>::MaybeType ConvertToInt32( |
| Isolate* isolate, HandleType<Object> input); |
| template <template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>) |
| V8_WARN_UNUSED_RESULT static HandleType<Number>::MaybeType ConvertToUint32( |
| Isolate* isolate, HandleType<Object> input); |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static MaybeHandle<Number> |
| ConvertToLength(Isolate* isolate, DirectHandle<Object> input); |
| template <template <typename> typename HandleType> |
| requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>) |
| EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) V8_WARN_UNUSED_RESULT static |
| typename HandleType<Number>::MaybeType |
| ConvertToIndex(Isolate* isolate, HandleType<Object> input, |
| MessageTemplate error_index); |
| }; |
| |
| V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, |
| Tagged<Object> obj); |
| V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, |
| Object::Conversion kind); |
| |
| struct Brief { |
| template <HeapObjectReferenceType kRefType> |
| explicit Brief(TaggedImpl<kRefType, Address> v) : value{v.ptr()} {} |
| template <typename T> |
| explicit Brief(T* v) : value{v->ptr()} {} |
| // {value} is a tagged heap object reference (weak or strong), equivalent to |
| // a MaybeObject's payload. It has a plain Address type to keep #includes |
| // lightweight. |
| const Address value; |
| }; |
| |
| V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, const Brief& v); |
| |
| // Objects should never have the weak tag; this variant is for overzealous |
| // checking. |
| V8_INLINE static bool HasWeakHeapObjectTag(const Tagged<Object> value) { |
| return HAS_WEAK_HEAP_OBJECT_TAG(value.ptr()); |
| } |
| |
| // Prints this object without details. |
| V8_EXPORT_PRIVATE void ShortPrint(Tagged<Object> obj, FILE* out = stdout); |
| |
| // Prints this object without details to a message accumulator. |
| V8_EXPORT_PRIVATE void ShortPrint(Tagged<Object> obj, |
| StringStream* accumulator); |
| |
| V8_EXPORT_PRIVATE void ShortPrint(Tagged<Object> obj, std::ostream& os); |
| |
| #ifdef OBJECT_PRINT |
| // For our gdb macros, we should perhaps change these in the future. |
| V8_EXPORT_PRIVATE void Print(Tagged<Object> obj); |
| |
| // Prints this object with details. |
| V8_EXPORT_PRIVATE void Print(Tagged<Object> obj, std::ostream& os); |
| |
| #else |
| inline void Print(Tagged<Object> obj) { ShortPrint(obj); } |
| inline void Print(Tagged<Object> obj, std::ostream& os) { ShortPrint(obj, os); } |
| #endif |
| |
| template <int start_offset, int end_offset, int size> |
| class FixedBodyDescriptor; |
| |
| template <int start_offset> |
| class FlexibleBodyDescriptor; |
| |
| template <int start_offset, int end_offset, int size> |
| class FixedWeakBodyDescriptor; |
| |
| template <int start_offset> |
| class FlexibleWeakBodyDescriptor; |
| |
| template <class ParentBodyDescriptor, class ChildBodyDescriptor> |
| class SubclassBodyDescriptor; |
| |
| enum EnsureElementsMode { |
| DONT_ALLOW_DOUBLE_ELEMENTS, |
| ALLOW_COPIED_DOUBLE_ELEMENTS, |
| ALLOW_CONVERTED_DOUBLE_ELEMENTS |
| }; |
| |
| // Indicator for one component of an AccessorPair. |
| enum AccessorComponent { ACCESSOR_GETTER, ACCESSOR_SETTER }; |
| |
| // Utility superclass for stack-allocated objects that must be updated |
| // on gc. It provides two ways for the gc to update instances, either |
| // iterating or updating after gc. |
| class Relocatable { |
| public: |
| explicit inline Relocatable(Isolate* isolate); |
| inline virtual ~Relocatable(); |
| virtual void IterateInstance(RootVisitor* v) {} |
| virtual void PostGarbageCollection() {} |
| |
| static void PostGarbageCollectionProcessing(Isolate* isolate); |
| static int ArchiveSpacePerThread(); |
| static char* ArchiveState(Isolate* isolate, char* to); |
| static char* RestoreState(Isolate* isolate, char* from); |
| static void Iterate(Isolate* isolate, RootVisitor* v); |
| static void Iterate(RootVisitor* v, Relocatable* top); |
| static char* Iterate(RootVisitor* v, char* t); |
| |
| Isolate* isolate() const { return isolate_; } |
| |
| private: |
| Isolate* isolate_; |
| Relocatable* prev_; |
| }; |
| |
| // BooleanBit is a helper class for setting and getting a bit in an integer. |
| class BooleanBit : public AllStatic { |
| public: |
| static inline bool get(int value, int bit_position) { |
| return (value & (1 << bit_position)) != 0; |
| } |
| |
| static inline int set(int value, int bit_position, bool v) { |
| if (v) { |
| value |= (1 << bit_position); |
| } else { |
| value &= ~(1 << bit_position); |
| } |
| return value; |
| } |
| }; |
| |
| // This is an RAII helper class to emit a store-store memory barrier when |
| // publishing objects allocated in the shared heap. |
| // |
| // This helper must be used in every Factory method that allocates a shared |
| // JSObject visible user JS code. This is also used in Object::ShareSlow when |
| // publishing newly shared JS primitives. |
| // |
| // While there is no default ordering guarantee for shared JS objects |
| // (e.g. without the use of Atomics methods or postMessage, data races on |
| // fields are observable), the internal VM state of a JS object must be safe |
| // for publishing so that other threads do not crash. |
| // |
| // This barrier does not provide synchronization for publishing JS shared |
| // objects. It only ensures the weaker "do not crash the VM" guarantee. |
| // |
| // In particular, note that memory barriers are invisible to TSAN. When |
| // concurrent marking is active, field accesses are performed with relaxed |
| // atomics, and TSAN is unable to detect data races in shared JS objects. When |
| // concurrent marking is inactive, unordered publishes of shared JS objects in |
| // JS code are reported as data race warnings by TSAN. |
| class V8_NODISCARD SharedObjectSafePublishGuard final { |
| public: |
| ~SharedObjectSafePublishGuard() { |
| // A release fence is used to prevent store-store reorderings of stores to |
| // VM-internal state of shared objects past any subsequent stores (i.e. the |
| // publish). |
| // |
| // On the loading side, we rely on neither the compiler nor the CPU |
| // reordering loads that are dependent on observing the address of the |
| // published shared object, like fields of the shared object. |
| std::atomic_thread_fence(std::memory_order_release); |
| } |
| }; |
| |
| // Like `SharedObjectsSafePublishGuard`, but only applies the fence |
| // if `apply_fence_` is shared. Also, applies TSAN_RELEASE after the release |
| // fence to disable TSAN false positives. |
| class V8_NODISCARD SharedObjectConditionalSafePublishGuard final { |
| public: |
| explicit SharedObjectConditionalSafePublishGuard(Tagged<HeapObject> object, |
| SharedFlag apply_fence) |
| : object_(object), apply_fence_(apply_fence) {} |
| explicit SharedObjectConditionalSafePublishGuard(Tagged<HeapObject> object, |
| AllocationType allocation) |
| : object_(object), apply_fence_(IsSharedAllocationType(allocation)) {} |
| ~SharedObjectConditionalSafePublishGuard() { |
| if (apply_fence_) { |
| std::atomic_thread_fence(std::memory_order_release); |
| TSAN_RELEASE(object_.address()); |
| } |
| } |
| |
| private: |
| // Required due to the raw Tagged<HeapObject> below. |
| DisallowGarbageCollection no_gc; |
| Tagged<HeapObject> object_; |
| SharedFlag apply_fence_; |
| }; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #include "src/objects/object-macros-undef.h" |
| |
| #endif // V8_OBJECTS_OBJECTS_H_ |