1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 #include "mozilla/MemoryReporting.h"
12 #include "jsfriendapi.h"
14 #include "js/friend/ErrorMessages.h" // JSErrNum
15 #include "js/GCVector.h"
16 #include "js/shadow/Zone.h" // JS::shadow::Zone
17 #include "js/Wrapper.h"
26 using PropertyDescriptorVector
= JS::GCVector
<JS::PropertyDescriptor
>;
29 struct AutoEnterOOMUnsafeRegion
;
32 class RelocationOverlay
;
35 /****************************************************************************/
40 enum class IntegrityLevel
{ Sealed
, Frozen
};
43 * The NewObjectKind allows an allocation site to specify the lifetime
44 * requirements that must be fixed at allocation time.
47 /* This is the default. Most objects are generic. */
51 * Objects which will not benefit from being allocated in the nursery
52 * (e.g. because they are known to have a long lifetime) may be allocated
53 * with this kind to place them immediately into the tenured generation.
58 // Forward declarations, required for later friend declarations.
59 bool PreventExtensions(JSContext
* cx
, JS::HandleObject obj
,
60 JS::ObjectOpResult
& result
);
61 bool SetImmutablePrototype(JSContext
* cx
, JS::HandleObject obj
,
67 * [SMDOC] JSObject layout
69 * A JavaScript object.
71 * This is the base class for all objects exposed to JS script (as well as some
72 * objects that are only accessed indirectly). Subclasses add additional fields
73 * and execution semantics. The runtime class of an arbitrary JSObject is
74 * identified by JSObject::getClass().
76 * All objects have a non-null Shape, stored in the cell header, which describes
77 * the current layout and set of property keys of the object.
79 * Each Shape has a pointer to a BaseShape. The BaseShape contains the object's
80 * prototype object, its class, and its realm.
82 * NOTE: Some operations can change the contents of an object (including class)
83 * in-place so avoid assuming an object with same pointer has same class
88 : public js::gc::CellWithTenuredGCPointer
<js::gc::Cell
, js::Shape
> {
90 // The Shape is stored in the cell header.
91 js::Shape
* shape() const { return headerPtr(); }
93 // Like shape(), but uses getAtomic to read the header word.
94 js::Shape
* shapeMaybeForwarded() const { return headerPtrAtomic(); }
97 // Ensure fixed slots have 8-byte alignment on 32-bit platforms.
102 friend class js::GCMarker
;
103 friend class js::GlobalObject
;
104 friend class js::Nursery
;
105 friend class js::gc::RelocationOverlay
;
106 friend bool js::PreventExtensions(JSContext
* cx
, JS::HandleObject obj
,
107 JS::ObjectOpResult
& result
);
108 friend bool js::SetImmutablePrototype(JSContext
* cx
, JS::HandleObject obj
,
112 const JSClass
* getClass() const { return shape()->getObjectClass(); }
113 bool hasClass(const JSClass
* c
) const { return getClass() == c
; }
115 js::LookupPropertyOp
getOpsLookupProperty() const {
116 return getClass()->getOpsLookupProperty();
118 js::DefinePropertyOp
getOpsDefineProperty() const {
119 return getClass()->getOpsDefineProperty();
121 js::HasPropertyOp
getOpsHasProperty() const {
122 return getClass()->getOpsHasProperty();
124 js::GetPropertyOp
getOpsGetProperty() const {
125 return getClass()->getOpsGetProperty();
127 js::SetPropertyOp
getOpsSetProperty() const {
128 return getClass()->getOpsSetProperty();
130 js::GetOwnPropertyOp
getOpsGetOwnPropertyDescriptor() const {
131 return getClass()->getOpsGetOwnPropertyDescriptor();
133 js::DeletePropertyOp
getOpsDeleteProperty() const {
134 return getClass()->getOpsDeleteProperty();
136 js::GetElementsOp
getOpsGetElements() const {
137 return getClass()->getOpsGetElements();
139 JSFunToStringOp
getOpsFunToString() const {
140 return getClass()->getOpsFunToString();
143 JS::Compartment
* compartment() const { return shape()->compartment(); }
144 JS::Compartment
* maybeCompartment() const { return compartment(); }
146 void initShape(js::Shape
* shape
) {
147 // Note: use Cell::Zone() instead of zone() because zone() relies on the
148 // shape we still have to initialize.
149 MOZ_ASSERT(Cell::zone() == shape
->zone());
150 initHeaderPtr(shape
);
152 void setShape(js::Shape
* shape
) {
153 MOZ_ASSERT(maybeCCWRealm() == shape
->realm());
157 static bool setFlag(JSContext
* cx
, JS::HandleObject obj
, js::ObjectFlag flag
);
159 bool hasFlag(js::ObjectFlag flag
) const {
160 return shape()->hasObjectFlag(flag
);
163 bool hasAnyFlag(js::ObjectFlags flags
) const {
164 return shape()->objectFlags().hasAnyFlag(flags
);
167 // Change this object's shape for a prototype mutation.
169 // Note: the caller must ensure the object has a mutable proto, is extensible,
171 static bool setProtoUnchecked(JSContext
* cx
, JS::HandleObject obj
,
172 js::Handle
<js::TaggedProto
> proto
);
174 // An object is marked IsUsedAsPrototype if it is (or was) another object's
175 // prototype. Optimization heuristics will make use of this flag.
177 // This flag is only relevant for static prototypes. Proxy traps can return
178 // objects without this flag set.
180 // NOTE: it's important to call setIsUsedAsPrototype *after* initializing the
181 // object's properties, because that avoids unnecessary shadowing checks and
184 // See: ReshapeForProtoMutation, ReshapeForShadowedProp
185 bool isUsedAsPrototype() const {
186 return hasFlag(js::ObjectFlag::IsUsedAsPrototype
);
188 static bool setIsUsedAsPrototype(JSContext
* cx
, JS::HandleObject obj
) {
189 return setFlag(cx
, obj
, js::ObjectFlag::IsUsedAsPrototype
);
192 bool useWatchtowerTestingLog() const {
193 return hasFlag(js::ObjectFlag::UseWatchtowerTestingLog
);
195 static bool setUseWatchtowerTestingLog(JSContext
* cx
, JS::HandleObject obj
) {
196 return setFlag(cx
, obj
, js::ObjectFlag::UseWatchtowerTestingLog
);
199 bool isGenerationCountedGlobal() const {
200 return hasFlag(js::ObjectFlag::GenerationCountedGlobal
);
202 static bool setGenerationCountedGlobal(JSContext
* cx
, JS::HandleObject obj
) {
203 return setFlag(cx
, obj
, js::ObjectFlag::GenerationCountedGlobal
);
206 // A "qualified" varobj is the object on which "qualified" variable
207 // declarations (i.e., those defined with "var") are kept.
209 // Conceptually, when a var binding is defined, it is defined on the
210 // innermost qualified varobj on the scope chain.
212 // Function scopes (CallObjects) are qualified varobjs, and there can be
213 // no other qualified varobj that is more inner for var bindings in that
214 // function. As such, all references to local var bindings in a function
215 // may be statically bound to the function scope. This is subject to
216 // further optimization. Unaliased bindings inside functions reside
217 // entirely on the frame, not in CallObjects.
219 // Global scopes are also qualified varobjs. It is possible to statically
220 // know, for a given script, that are no more inner qualified varobjs, so
221 // free variable references can be statically bound to the global.
223 // Finally, there are non-syntactic qualified varobjs used by embedders
224 // (e.g., Gecko and XPConnect), as they often wish to run scripts under a
225 // scope that captures var bindings.
226 inline bool isQualifiedVarObj() const;
227 static bool setQualifiedVarObj(JSContext
* cx
, JS::HandleObject obj
) {
228 return setFlag(cx
, obj
, js::ObjectFlag::QualifiedVarObj
);
231 // An "unqualified" varobj is the object on which "unqualified"
232 // assignments (i.e., bareword assignments for which the LHS does not
233 // exist on the scope chain) are kept.
234 inline bool isUnqualifiedVarObj() const;
236 // Once the "invalidated teleporting" flag is set for an object, it is never
237 // cleared and it may cause the JITs to insert additional guards when
238 // accessing properties on this object. While the flag remains clear, the
239 // shape teleporting optimization can be used to avoid those extra checks.
241 // The flag is set on the object if either:
243 // * Its own proto was mutated or it was on the proto chain of an object that
244 // had its proto mutated.
246 // * It was on the proto chain of an object that started shadowing a property
250 // - ReshapeForProtoMutation
251 // - ReshapeForShadowedProp
252 // - ProtoChainSupportsTeleporting
253 inline bool hasInvalidatedTeleporting() const;
254 static bool setInvalidatedTeleporting(JSContext
* cx
, JS::HandleObject obj
) {
255 MOZ_ASSERT(obj
->isUsedAsPrototype());
256 MOZ_ASSERT(obj
->hasStaticPrototype(),
257 "teleporting as a concept is only applicable to static "
258 "(not dynamically-computed) prototypes");
259 return setFlag(cx
, obj
, js::ObjectFlag::InvalidatedTeleporting
);
263 * Whether there may be "interesting symbol" properties on this object. An
264 * interesting symbol is a symbol for which symbol->isInterestingSymbol()
267 MOZ_ALWAYS_INLINE
bool maybeHasInterestingSymbolProperty() const;
269 inline bool needsProxyGetSetResultValidation() const;
273 void traceChildren(JSTracer
* trc
);
275 void fixupAfterMovingGC() {}
277 static const JS::TraceKind TraceKind
= JS::TraceKind::Object
;
279 static constexpr size_t thingSize(js::gc::AllocKind kind
);
281 MOZ_ALWAYS_INLINE
JS::Zone
* zone() const {
282 MOZ_ASSERT_IF(!isTenured(), nurseryZone() == shape()->zone());
283 return shape()->zone();
285 MOZ_ALWAYS_INLINE
JS::shadow::Zone
* shadowZone() const {
286 return JS::shadow::Zone::from(zone());
288 MOZ_ALWAYS_INLINE
JS::Zone
* zoneFromAnyThread() const {
289 MOZ_ASSERT_IF(!isTenured(),
290 nurseryZoneFromAnyThread() == shape()->zoneFromAnyThread());
291 return shape()->zoneFromAnyThread();
293 MOZ_ALWAYS_INLINE
JS::shadow::Zone
* shadowZoneFromAnyThread() const {
294 return JS::shadow::Zone::from(zoneFromAnyThread());
296 static MOZ_ALWAYS_INLINE
void postWriteBarrier(void* cellp
, JSObject
* prev
,
298 js::gc::PostWriteBarrierImpl
<JSObject
>(cellp
, prev
, next
);
301 /* Return the allocKind we would use if we were to tenure this object. */
302 js::gc::AllocKind
allocKindForTenure(const js::Nursery
& nursery
) const;
304 bool canHaveFixedElements() const;
306 size_t tenuredSizeOfThis() const {
307 MOZ_ASSERT(isTenured());
308 return js::gc::Arena::thingSize(asTenured().getAllocKind());
311 void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
,
313 JS::RuntimeSizes
* runtimeSizes
);
315 // We can only use addSizeOfExcludingThis on tenured objects: it assumes it
316 // can apply mallocSizeOf to bits and pieces of the object, whereas objects
317 // in the nursery may have those bits and pieces allocated in the nursery
318 // along with them, and are not each their own malloc blocks.
319 size_t sizeOfIncludingThisInNursery() const;
322 static void debugCheckNewObject(js::Shape
* shape
, js::gc::AllocKind allocKind
,
325 static void debugCheckNewObject(js::Shape
* shape
, js::gc::AllocKind allocKind
,
326 js::gc::Heap heap
) {}
330 * We permit proxies to dynamically compute their prototype if desired.
331 * (Not all proxies will so desire: in particular, most DOM proxies can
332 * track their prototype with a single, nullable JSObject*.) If a proxy
333 * so desires, we store (JSObject*)0x1 in the proto field of the object's
336 * We offer three ways to get an object's prototype:
338 * 1. obj->staticPrototype() returns the prototype, but it asserts if obj
339 * is a proxy, and the proxy has opted to dynamically compute its
340 * prototype using a getPrototype() handler.
341 * 2. obj->taggedProto() returns a TaggedProto, which can be tested to
342 * check if the proto is an object, nullptr, or lazily computed.
343 * 3. js::GetPrototype(cx, obj, &proto) computes the proto of an object.
344 * If obj is a proxy with dynamically-computed prototype, this code may
345 * perform arbitrary behavior (allocation, GC, run JS) while computing
349 js::TaggedProto
taggedProto() const { return shape()->proto(); }
351 bool uninlinedIsProxyObject() const;
353 JSObject
* staticPrototype() const {
354 MOZ_ASSERT(hasStaticPrototype());
355 return taggedProto().toObjectOrNull();
358 // Normal objects and a subset of proxies have an uninteresting, static
359 // (albeit perhaps mutable) [[Prototype]]. For such objects the
360 // [[Prototype]] is just a value returned when needed for accesses, or
361 // modified in response to requests. These objects store the
362 // [[Prototype]] directly within |obj->group()|.
363 bool hasStaticPrototype() const { return !hasDynamicPrototype(); }
365 // The remaining proxies have a [[Prototype]] requiring dynamic computation
366 // for every access, going through the proxy handler {get,set}Prototype and
367 // setImmutablePrototype methods. (Wrappers particularly use this to keep
368 // the wrapper/wrappee [[Prototype]]s consistent.)
369 bool hasDynamicPrototype() const {
370 bool dynamic
= taggedProto().isDynamic();
371 MOZ_ASSERT_IF(dynamic
, uninlinedIsProxyObject());
375 // True iff this object's [[Prototype]] is immutable. Must be called only
376 // on objects with a static [[Prototype]]!
377 inline bool staticPrototypeIsImmutable() const;
380 * Environment chains.
382 * The environment chain of an object is the link in the search path when
383 * a script does a name lookup on an environment object. For JS internal
384 * environment objects --- Call, LexicalEnvironment, and WithEnvironment
385 * --- the chain is stored in the first fixed slot of the object. For
386 * other environment objects, the chain goes directly to the global.
388 * In code which is not marked hasNonSyntacticScope, environment chains
389 * can contain only syntactic environment objects (see
390 * IsSyntacticEnvironment) with a global object at the root as the
391 * environment of the outermost non-function script. In
392 * hasNonSyntacticScope code, the environment of the outermost
393 * non-function script might not be a global object, and can have a mix of
394 * other objects above it before the global object is reached.
398 * Get the enclosing environment of an object. When called on a
399 * non-EnvironmentObject, this will just be the global (the name
400 * "enclosing environment" still applies in this situation because
401 * non-EnvironmentObjects can be on the environment chain).
403 inline JSObject
* enclosingEnvironment() const;
405 // Cross-compartment wrappers are not associated with a single realm/global,
406 // so these methods assert the object is not a CCW.
407 inline js::GlobalObject
& nonCCWGlobal() const;
409 JS::Realm
* nonCCWRealm() const {
410 MOZ_ASSERT(!js::UninlinedIsCrossCompartmentWrapper(this));
411 return shape()->realm();
413 bool hasSameRealmAs(JSContext
* cx
) const;
415 // Returns the object's realm even if the object is a CCW (be careful, in
416 // this case the realm is not very meaningful because wrappers are shared by
417 // all realms in the compartment).
418 JS::Realm
* maybeCCWRealm() const { return shape()->realm(); }
421 * ES5 meta-object properties and operations.
425 // Indicates whether a non-proxy is extensible. Don't call on proxies!
426 // This method really shouldn't exist -- but there are a few internal
427 // places that want it (JITs and the like), and it'd be a pain to mark them
429 inline bool nonProxyIsExtensible() const;
430 bool uninlinedNonProxyIsExtensible() const;
434 * Back to generic stuff.
436 MOZ_ALWAYS_INLINE
bool isCallable() const;
437 MOZ_ALWAYS_INLINE
bool isConstructor() const;
438 MOZ_ALWAYS_INLINE JSNative
callHook() const;
439 MOZ_ALWAYS_INLINE JSNative
constructHook() const;
441 bool isBackgroundFinalized() const;
443 MOZ_ALWAYS_INLINE
void finalize(JS::GCContext
* gcx
);
446 static bool nonNativeSetProperty(JSContext
* cx
, js::HandleObject obj
,
447 js::HandleId id
, js::HandleValue v
,
448 js::HandleValue receiver
,
449 JS::ObjectOpResult
& result
);
450 static bool nonNativeSetElement(JSContext
* cx
, js::HandleObject obj
,
451 uint32_t index
, js::HandleValue v
,
452 js::HandleValue receiver
,
453 JS::ObjectOpResult
& result
);
455 static void swap(JSContext
* cx
, JS::HandleObject a
, JS::HandleObject b
,
456 js::AutoEnterOOMUnsafeRegion
& oomUnsafe
);
459 * In addition to the generic object interface provided by JSObject,
460 * specific types of objects may provide additional operations. To access,
461 * these addition operations, callers should use the pattern:
463 * if (obj.is<XObject>()) {
464 * XObject& x = obj.as<XObject>();
468 * These XObject classes form a hierarchy. For example, for a cloned block
469 * object, the following predicates are true: is<ClonedBlockObject>,
470 * is<NestedScopeObject> and is<ScopeObject>. Each of these has a
471 * respective class that derives and adds operations.
473 * A class XObject is defined in a vm/XObject{.h, .cpp, -inl.h} file
474 * triplet (along with any class YObject that derives XObject).
476 * Note that X represents a low-level representation and does not query the
477 * [[Class]] property of object defined by the spec: use |JS::GetBuiltinClass|
482 inline bool is() const {
483 return getClass() == &T::class_
;
488 MOZ_ASSERT(this->is
<T
>());
489 return *static_cast<T
*>(this);
493 const T
& as() const {
494 MOZ_ASSERT(this->is
<T
>());
495 return *static_cast<const T
*>(this);
499 * True if either this or CheckedUnwrap(this) is an object of class T.
500 * (Only two objects are checked, regardless of how many wrappers there
503 * /!\ Note: This can be true at one point, but false later for the same
504 * object, thanks to js::NukeCrossCompartmentWrapper and friends.
510 * Unwrap and downcast to class T.
512 * Precondition: `this->canUnwrapAs<T>()`. Note that it's not enough to
513 * have checked this at some point in the past; if there's any doubt as to
514 * whether js::Nuke* could have been called in the meantime, check again.
520 * Tries to unwrap and downcast to class T. Returns nullptr if (and only if) a
521 * wrapper with a security policy is involved. Crashes in all builds if the
522 * (possibly unwrapped) object is not of class T (for example, because it's a
526 inline T
* maybeUnwrapAs();
529 * Tries to unwrap and downcast to an object with class |clasp|. Returns
530 * nullptr if (and only if) a wrapper with a security policy is involved.
531 * Crashes in all builds if the (possibly unwrapped) object doesn't have class
532 * |clasp| (for example, because it's a dead wrapper).
534 inline JSObject
* maybeUnwrapAs(const JSClass
* clasp
);
537 * Tries to unwrap and downcast to class T. Returns nullptr if a wrapper with
538 * a security policy is involved or if the object does not have class T.
543 #if defined(DEBUG) || defined(JS_JITSPEW)
544 void dump(js::GenericPrinter
& fp
) const;
548 // Maximum size in bytes of a JSObject.
550 static constexpr size_t MAX_BYTE_SIZE
=
551 3 * sizeof(void*) + 16 * sizeof(JS::Value
);
553 static constexpr size_t MAX_BYTE_SIZE
=
554 4 * sizeof(void*) + 16 * sizeof(JS::Value
);
560 // To help avoid writing Spectre-unsafe code, we only allow MacroAssembler
561 // to call the method below.
562 friend class js::jit::MacroAssembler
;
564 static constexpr size_t offsetOfShape() { return offsetOfHeaderPtr(); }
567 JSObject(const JSObject
& other
) = delete;
568 void operator=(const JSObject
& other
) = delete;
571 // For the allocator only, to be used with placement new.
572 friend class js::gc::GCRuntime
;
573 JSObject() = default;
577 inline bool JSObject::is
<JSObject
>() const {
581 template <typename Wrapper
>
582 template <typename U
>
583 MOZ_ALWAYS_INLINE
JS::Handle
<U
*> js::RootedOperations
<JSObject
*, Wrapper
>::as()
585 const Wrapper
& self
= *static_cast<const Wrapper
*>(this);
586 MOZ_ASSERT(self
->template is
<U
>());
587 return Handle
<U
*>::fromMarkedLocation(
588 reinterpret_cast<U
* const*>(self
.address()));
591 template <typename Wrapper
>
593 MOZ_ALWAYS_INLINE
JS::Handle
<U
*> js::HandleOperations
<JSObject
*, Wrapper
>::as()
595 const JS::Handle
<JSObject
*>& self
=
596 *static_cast<const JS::Handle
<JSObject
*>*>(this);
597 MOZ_ASSERT(self
->template is
<U
>());
598 return Handle
<U
*>::fromMarkedLocation(
599 reinterpret_cast<U
* const*>(self
.address()));
603 bool JSObject::canUnwrapAs() {
604 static_assert(!std::is_convertible_v
<T
*, js::Wrapper
*>,
605 "T can't be a Wrapper type; this function discards wrappers");
610 JSObject
* obj
= js::CheckedUnwrapStatic(this);
611 return obj
&& obj
->is
<T
>();
615 T
& JSObject::unwrapAs() {
616 static_assert(!std::is_convertible_v
<T
*, js::Wrapper
*>,
617 "T can't be a Wrapper type; this function discards wrappers");
623 // Since the caller just called canUnwrapAs<T>(), which does a
624 // CheckedUnwrap, this does not need to repeat the security check.
625 JSObject
* unwrapped
= js::UncheckedUnwrap(this);
626 MOZ_ASSERT(js::CheckedUnwrapStatic(this) == unwrapped
,
627 "check that the security check we skipped really is redundant");
628 return unwrapped
->as
<T
>();
632 inline T
* JSObject::maybeUnwrapAs() {
633 static_assert(!std::is_convertible_v
<T
*, js::Wrapper
*>,
634 "T can't be a Wrapper type; this function discards wrappers");
640 JSObject
* unwrapped
= js::CheckedUnwrapStatic(this);
645 if (MOZ_LIKELY(unwrapped
->is
<T
>())) {
646 return &unwrapped
->as
<T
>();
649 MOZ_CRASH("Invalid object. Dead wrapper?");
652 inline JSObject
* JSObject::maybeUnwrapAs(const JSClass
* clasp
) {
653 if (hasClass(clasp
)) {
657 JSObject
* unwrapped
= js::CheckedUnwrapStatic(this);
662 if (MOZ_LIKELY(unwrapped
->hasClass(clasp
))) {
666 MOZ_CRASH("Invalid object. Dead wrapper?");
670 T
* JSObject::maybeUnwrapIf() {
671 static_assert(!std::is_convertible_v
<T
*, js::Wrapper
*>,
672 "T can't be a Wrapper type; this function discards wrappers");
678 JSObject
* unwrapped
= js::CheckedUnwrapStatic(this);
679 return (unwrapped
&& unwrapped
->is
<T
>()) ? &unwrapped
->as
<T
>() : nullptr;
683 * The only sensible way to compare JSObject with == is by identity. We use
684 * const& instead of * as a syntactic way to assert non-null. This leads to an
685 * abundance of address-of operators to identity. Hence this overload.
687 static MOZ_ALWAYS_INLINE
bool operator==(const JSObject
& lhs
,
688 const JSObject
& rhs
) {
692 static MOZ_ALWAYS_INLINE
bool operator!=(const JSObject
& lhs
,
693 const JSObject
& rhs
) {
697 // Size of the various GC thing allocation sizes used for objects.
698 struct JSObject_Slots0
: JSObject
{
701 struct JSObject_Slots2
: JSObject
{
705 struct JSObject_Slots4
: JSObject
{
709 struct JSObject_Slots7
: JSObject
{
710 // Only used for extended functions which are required to have exactly seven
711 // fixed slots due to JIT assumptions.
715 struct JSObject_Slots8
: JSObject
{
719 struct JSObject_Slots12
: JSObject
{
721 js::Value fslots
[12];
723 struct JSObject_Slots16
: JSObject
{
725 js::Value fslots
[16];
729 constexpr size_t JSObject::thingSize(js::gc::AllocKind kind
) {
730 MOZ_ASSERT(IsObjectAllocKind(kind
));
731 constexpr uint8_t objectSizes
[] = {
732 #define EXPAND_OJBECT_SIZE(_1, _2, _3, sizedType, _4, _5, _6) sizeof(sizedType),
733 FOR_EACH_OBJECT_ALLOCKIND(EXPAND_OJBECT_SIZE
)};
734 return objectSizes
[size_t(kind
)];
739 // Returns true if object may possibly use JSObject::swap. The JITs may better
740 // optimize objects that can never swap (and thus change their type).
742 // If ObjectMayBeSwapped is false, it is safe to guard on pointer identity to
743 // test immutable features of the object. For example, the target of a
744 // JSFunction will not change. Note: the object can still be moved by GC.
745 extern bool ObjectMayBeSwapped(const JSObject
* obj
);
747 extern bool DefineFunctions(JSContext
* cx
, HandleObject obj
,
748 const JSFunctionSpec
* fs
);
750 /* ES6 draft rev 36 (2015 March 17) 7.1.1 ToPrimitive(vp[, preferredType]) */
751 extern bool ToPrimitiveSlow(JSContext
* cx
, JSType hint
, MutableHandleValue vp
);
753 inline bool ToPrimitive(JSContext
* cx
, MutableHandleValue vp
) {
754 if (vp
.isPrimitive()) {
757 return ToPrimitiveSlow(cx
, JSTYPE_UNDEFINED
, vp
);
760 inline bool ToPrimitive(JSContext
* cx
, JSType preferredType
,
761 MutableHandleValue vp
) {
762 if (vp
.isPrimitive()) {
765 return ToPrimitiveSlow(cx
, preferredType
, vp
);
769 * toString support. (This isn't called GetClassName because there's a macro in
770 * <windows.h> with that name.)
772 MOZ_ALWAYS_INLINE
const char* GetObjectClassName(JSContext
* cx
,
776 * Prepare a |this| object to be returned to script. This includes replacing
777 * Windows with their corresponding WindowProxy.
779 * Helpers are also provided to first extract the |this| from specific
780 * types of environment.
782 JSObject
* GetThisObject(JSObject
* obj
);
784 JSObject
* GetThisObjectOfLexical(JSObject
* env
);
786 JSObject
* GetThisObjectOfWith(JSObject
* env
);
792 // ES6 9.1.15 GetPrototypeFromConstructor.
793 extern bool GetPrototypeFromConstructor(JSContext
* cx
,
794 js::HandleObject newTarget
,
795 JSProtoKey intrinsicDefaultProto
,
796 js::MutableHandleObject proto
);
798 // https://tc39.github.io/ecma262/#sec-getprototypefromconstructor
800 // Determine which [[Prototype]] to use when creating a new object using a
801 // builtin constructor.
803 // This sets `proto` to `nullptr` to mean "the builtin prototype object for
804 // this type in the current realm", the common case.
806 // We could set it to `cx->global()->getOrCreatePrototype(protoKey)`, but
807 // nullptr gets a fast path in e.g. js::NewObjectWithClassProtoCommon.
809 // intrinsicDefaultProto can be JSProto_Null if there's no appropriate
810 // JSProtoKey enum; but we then select the wrong prototype object in a
811 // multi-realm corner case (see bug 1515167).
812 MOZ_ALWAYS_INLINE
bool GetPrototypeFromBuiltinConstructor(
813 JSContext
* cx
, const CallArgs
& args
, JSProtoKey intrinsicDefaultProto
,
814 js::MutableHandleObject proto
) {
815 // We can skip the "prototype" lookup in the two common cases:
816 // 1. Builtin constructor called without `new`, as in `obj = Object();`.
817 // 2. Builtin constructor called with `new`, as in `obj = new Object();`.
819 // Cases that can't take the fast path include `new MySubclassOfObject()`,
820 // `new otherGlobal.Object()`, and `Reflect.construct(Object, [], Date)`.
821 if (!args
.isConstructing() ||
822 &args
.newTarget().toObject() == &args
.callee()) {
823 MOZ_ASSERT(args
.callee().hasSameRealmAs(cx
));
828 // We're calling this constructor from a derived class, retrieve the
829 // actual prototype from newTarget.
830 RootedObject
newTarget(cx
, &args
.newTarget().toObject());
831 return GetPrototypeFromConstructor(cx
, newTarget
, intrinsicDefaultProto
,
835 /* ES6 draft rev 32 (2015 Feb 2) 6.2.4.5 ToPropertyDescriptor(Obj) */
836 bool ToPropertyDescriptor(JSContext
* cx
, HandleValue descval
,
838 MutableHandle
<JS::PropertyDescriptor
> desc
);
841 * Throw a TypeError if desc.getter() or setter() is not
842 * callable. This performs exactly the checks omitted by ToPropertyDescriptor
843 * when checkAccessors is false.
845 Result
<> CheckPropertyDescriptorAccessors(JSContext
* cx
,
846 Handle
<JS::PropertyDescriptor
> desc
);
848 void CompletePropertyDescriptor(MutableHandle
<JS::PropertyDescriptor
> desc
);
851 * Read property descriptors from props, as for Object.defineProperties. See
852 * ES5 15.2.3.7 steps 3-5.
854 extern bool ReadPropertyDescriptors(
855 JSContext
* cx
, HandleObject props
, bool checkAccessors
,
856 MutableHandleIdVector ids
, MutableHandle
<PropertyDescriptorVector
> descs
);
858 /* Read the name using a dynamic lookup on the scopeChain. */
859 extern bool LookupName(JSContext
* cx
, Handle
<PropertyName
*> name
,
860 HandleObject scopeChain
, MutableHandleObject objp
,
861 MutableHandleObject pobjp
, PropertyResult
* propp
);
863 extern bool LookupNameNoGC(JSContext
* cx
, PropertyName
* name
,
864 JSObject
* scopeChain
, JSObject
** objp
,
865 NativeObject
** pobjp
, PropertyResult
* propp
);
868 * Like LookupName except returns the global object if 'name' is not found in
869 * any preceding scope.
871 * Additionally, pobjp and propp are not needed by callers so they are not
874 extern bool LookupNameWithGlobalDefault(JSContext
* cx
,
875 Handle
<PropertyName
*> name
,
876 HandleObject scopeChain
,
877 MutableHandleObject objp
);
880 * Like LookupName except returns the unqualified var object if 'name' is not
881 * found in any preceding scope. Normally the unqualified var object is the
882 * global. If the value for the name in the looked-up scope is an
883 * uninitialized lexical, an UninitializedLexicalObject is returned.
885 * Additionally, pobjp is not needed by callers so it is not returned.
887 extern bool LookupNameUnqualified(JSContext
* cx
, Handle
<PropertyName
*> name
,
888 HandleObject scopeChain
,
889 MutableHandleObject objp
);
896 * Family of Pure property lookup functions. The bool return does NOT have the
897 * standard SpiderMonkey semantics. The return value means "can this operation
898 * be performed and produce a valid result without any side effects?". If any of
899 * these return true, then the outparam can be inspected to determine the
903 bool LookupPropertyPure(JSContext
* cx
, JSObject
* obj
, jsid id
,
904 NativeObject
** objp
, PropertyResult
* propp
);
906 bool LookupOwnPropertyPure(JSContext
* cx
, JSObject
* obj
, jsid id
,
907 PropertyResult
* propp
);
909 bool GetPropertyPure(JSContext
* cx
, JSObject
* obj
, jsid id
, Value
* vp
);
911 bool GetOwnPropertyPure(JSContext
* cx
, JSObject
* obj
, jsid id
, Value
* vp
,
914 bool GetGetterPure(JSContext
* cx
, JSObject
* obj
, jsid id
, JSFunction
** fp
);
916 bool GetOwnGetterPure(JSContext
* cx
, JSObject
* obj
, jsid id
, JSFunction
** fp
);
918 bool GetOwnNativeGetterPure(JSContext
* cx
, JSObject
* obj
, jsid id
,
921 bool HasOwnDataPropertyPure(JSContext
* cx
, JSObject
* obj
, jsid id
,
925 * Like JS::FromPropertyDescriptor, but ignore desc.object() and always set vp
926 * to an object on success.
928 * Use JS::FromPropertyDescriptor for getOwnPropertyDescriptor, since
929 * desc.object() is used to indicate whether a result was found or not. Use
930 * this instead for defineProperty: it would be senseless to define a "missing"
933 extern bool FromPropertyDescriptorToObject(JSContext
* cx
,
934 Handle
<JS::PropertyDescriptor
> desc
,
935 MutableHandleValue vp
);
937 // obj is a JSObject*, but we root it immediately up front. We do it
938 // that way because we need a Rooted temporary in this method anyway.
939 extern bool IsPrototypeOf(JSContext
* cx
, HandleObject protoObj
, JSObject
* obj
,
942 /* Wrap boolean, number or string as Boolean, Number or String object. */
943 extern JSObject
* PrimitiveToObject(JSContext
* cx
, const Value
& v
);
944 extern JSProtoKey
PrimitiveToProtoKey(JSContext
* cx
, const Value
& v
);
950 JSObject
* ToObjectSlowForPropertyAccess(JSContext
* cx
, JS::HandleValue val
,
951 int valIndex
, HandleId key
);
952 JSObject
* ToObjectSlowForPropertyAccess(JSContext
* cx
, JS::HandleValue val
,
954 Handle
<PropertyName
*> key
);
955 JSObject
* ToObjectSlowForPropertyAccess(JSContext
* cx
, JS::HandleValue val
,
956 int valIndex
, HandleValue keyValue
);
958 MOZ_ALWAYS_INLINE JSObject
* ToObjectFromStackForPropertyAccess(JSContext
* cx
,
963 return &vp
.toObject();
965 return js::ToObjectSlowForPropertyAccess(cx
, vp
, vpIndex
, key
);
967 MOZ_ALWAYS_INLINE JSObject
* ToObjectFromStackForPropertyAccess(
968 JSContext
* cx
, HandleValue vp
, int vpIndex
, Handle
<PropertyName
*> key
) {
970 return &vp
.toObject();
972 return js::ToObjectSlowForPropertyAccess(cx
, vp
, vpIndex
, key
);
974 MOZ_ALWAYS_INLINE JSObject
* ToObjectFromStackForPropertyAccess(
975 JSContext
* cx
, HandleValue vp
, int vpIndex
, HandleValue key
) {
977 return &vp
.toObject();
979 return js::ToObjectSlowForPropertyAccess(cx
, vp
, vpIndex
, key
);
983 * Report a TypeError: "so-and-so is not an object".
984 * Using NotNullObject is usually less code.
986 extern void ReportNotObject(JSContext
* cx
, const Value
& v
);
988 inline JSObject
* RequireObject(JSContext
* cx
, HandleValue v
) {
990 return &v
.toObject();
992 ReportNotObject(cx
, v
);
997 * Report a TypeError: "SOMETHING must be an object, got VALUE".
998 * Using NotNullObject is usually less code.
1000 * By default this function will attempt to report the expression which computed
1001 * the value which given as argument. This can be disabled by using
1002 * JSDVG_IGNORE_STACK.
1004 extern void ReportNotObject(JSContext
* cx
, JSErrNum err
, int spindex
,
1007 inline JSObject
* RequireObject(JSContext
* cx
, JSErrNum err
, int spindex
,
1010 return &v
.toObject();
1012 ReportNotObject(cx
, err
, spindex
, v
);
1016 extern void ReportNotObject(JSContext
* cx
, JSErrNum err
, HandleValue v
);
1018 inline JSObject
* RequireObject(JSContext
* cx
, JSErrNum err
, HandleValue v
) {
1020 return &v
.toObject();
1022 ReportNotObject(cx
, err
, v
);
1027 * Report a TypeError: "N-th argument of FUN must be an object, got VALUE".
1028 * Using NotNullObjectArg is usually less code.
1030 extern void ReportNotObjectArg(JSContext
* cx
, const char* nth
, const char* fun
,
1033 inline JSObject
* RequireObjectArg(JSContext
* cx
, const char* nth
,
1034 const char* fun
, HandleValue v
) {
1036 return &v
.toObject();
1038 ReportNotObjectArg(cx
, nth
, fun
, v
);
1042 extern bool GetFirstArgumentAsObject(JSContext
* cx
, const CallArgs
& args
,
1044 MutableHandleObject objp
);
1046 /* Helper for throwing, always returns false. */
1047 extern bool Throw(JSContext
* cx
, HandleId id
, unsigned errorNumber
,
1048 const char* details
= nullptr);
1051 * ES6 rev 29 (6 Dec 2014) 7.3.13. Mark obj as non-extensible, and adjust each
1052 * of obj's own properties' attributes appropriately: each property becomes
1053 * non-configurable, and if level == Frozen, data properties become
1054 * non-writable as well.
1056 extern bool SetIntegrityLevel(JSContext
* cx
, HandleObject obj
,
1057 IntegrityLevel level
);
1059 inline bool FreezeObject(JSContext
* cx
, HandleObject obj
) {
1060 return SetIntegrityLevel(cx
, obj
, IntegrityLevel::Frozen
);
1064 * ES6 rev 29 (6 Dec 2014) 7.3.14. Code shared by Object.isSealed and
1067 extern bool TestIntegrityLevel(JSContext
* cx
, HandleObject obj
,
1068 IntegrityLevel level
, bool* resultp
);
1070 [[nodiscard
]] extern JSObject
* SpeciesConstructor(
1071 JSContext
* cx
, HandleObject obj
, HandleObject defaultCtor
,
1072 bool (*isDefaultSpecies
)(JSContext
*, JSFunction
*));
1074 [[nodiscard
]] extern JSObject
* SpeciesConstructor(
1075 JSContext
* cx
, HandleObject obj
, JSProtoKey ctorKey
,
1076 bool (*isDefaultSpecies
)(JSContext
*, JSFunction
*));
1078 extern bool GetObjectFromIncumbentGlobal(JSContext
* cx
,
1079 MutableHandleObject obj
);
1082 inline bool IsObjectValueInCompartment(const Value
& v
, JS::Compartment
* comp
) {
1083 if (!v
.isObject()) {
1086 return v
.toObject().compartment() == comp
;
1091 * A generic trace hook that calls the object's 'trace' method.
1093 * If you are introducing a new JSObject subclass, MyObject, that needs a custom
1094 * JSClassOps::trace function, it's often helpful to write `trace` as a
1095 * non-static member function, since `this` will the correct type. In this case,
1096 * you can use `CallTraceMethod<MyObject>` as your JSClassOps::trace value.
1098 template <typename ObjectSubclass
>
1099 void CallTraceMethod(JSTracer
* trc
, JSObject
* obj
) {
1100 obj
->as
<ObjectSubclass
>().trace(trc
);
1103 #ifdef JS_HAS_CTYPES
1107 extern size_t SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf
,
1110 } // namespace ctypes
1115 void AssertJSClassInvariants(const JSClass
* clasp
);
1118 } /* namespace js */
1120 #endif /* vm_JSObject_h */