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