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/. */
7 /* JSClass definition and its component types, plus related interfaces. */
12 #include "mozilla/Attributes.h"
13 #include "mozilla/Maybe.h"
17 #include "js/CallArgs.h"
18 #include "js/HeapAPI.h"
20 #include "js/TypeDecls.h"
23 * A JSClass acts as a vtable for JS objects that allows JSAPI clients to
24 * control various aspects of the behavior of an object like property lookup.
25 * It contains some engine-private extensions that allows more control over
26 * object behavior and, e.g., allows custom slow layout.
30 struct JSFunctionSpec
;
36 // These are equal to js::FunctionClass / js::ExtendedFunctionClass.
37 extern JS_PUBLIC_DATA
const JSClass
* const FunctionClassPtr
;
38 extern JS_PUBLIC_DATA
const JSClass
* const FunctionExtendedClassPtr
;
45 * Per ES6, the [[DefineOwnProperty]] internal method has three different
48 * - It can throw an exception (which we indicate by returning false).
50 * - It can return true, indicating unvarnished success.
52 * - It can return false, indicating "strict failure". The property could
53 * not be defined. It's an error, but no exception was thrown.
55 * It's not just [[DefineOwnProperty]]: all the mutating internal methods have
56 * the same three outcomes. (The other affected internal methods are [[Set]],
57 * [[Delete]], [[SetPrototypeOf]], and [[PreventExtensions]].)
59 * If you think this design is awful, you're not alone. But as it's the
60 * standard, we must represent these boolean "success" values somehow.
61 * ObjectOpSuccess is the class for this. It's like a bool, but when it's false
62 * it also stores an error code.
66 * ObjectOpResult result;
67 * if (!DefineProperty(cx, obj, id, ..., result)) {
71 * return result.reportError(cx, obj, id);
74 * Users don't have to call `result.report()`; another possible ending is:
76 * argv.rval().setBoolean(result.ok());
79 class ObjectOpResult
{
82 * code_ is either one of the special codes OkCode or Uninitialized, or an
83 * error code. For now the error codes are JS friend API and are defined in
84 * js/public/friend/ErrorNumbers.msg.
86 * code_ is uintptr_t (rather than uint32_t) for the convenience of the
87 * JITs, which would otherwise have to deal with either padding or stack
88 * alignment on 64-bit platforms.
93 enum SpecialCodes
: uintptr_t { OkCode
= 0, Uninitialized
= uintptr_t(-1) };
95 ObjectOpResult() : code_(Uninitialized
) {}
97 /* Return true if succeed() was called. */
99 MOZ_ASSERT(code_
!= Uninitialized
);
100 return code_
== OkCode
;
103 explicit operator bool() const { return ok(); }
105 /* Set this ObjectOpResult to true and return true. */
112 * Set this ObjectOpResult to false with an error code.
114 * Always returns true, as a convenience. Typical usage will be:
116 * if (funny condition) {
117 * return result.fail(JSMSG_CANT_DO_THE_THINGS);
120 * The true return value indicates that no exception is pending, and it
121 * would be OK to ignore the failure and continue.
123 bool fail(uint32_t msg
) {
124 MOZ_ASSERT(msg
!= OkCode
);
129 JS_PUBLIC_API
bool failCantRedefineProp();
130 JS_PUBLIC_API
bool failReadOnly();
131 JS_PUBLIC_API
bool failGetterOnly();
132 JS_PUBLIC_API
bool failCantDelete();
134 JS_PUBLIC_API
bool failCantSetInterposed();
135 JS_PUBLIC_API
bool failCantDefineWindowElement();
136 JS_PUBLIC_API
bool failCantDeleteWindowElement();
137 JS_PUBLIC_API
bool failCantDefineWindowNamedProperty();
138 JS_PUBLIC_API
bool failCantDeleteWindowNamedProperty();
139 JS_PUBLIC_API
bool failCantPreventExtensions();
140 JS_PUBLIC_API
bool failCantSetProto();
141 JS_PUBLIC_API
bool failNoNamedSetter();
142 JS_PUBLIC_API
bool failNoIndexedSetter();
143 JS_PUBLIC_API
bool failNotDataDescriptor();
144 JS_PUBLIC_API
bool failInvalidDescriptor();
146 // Careful: This case has special handling in Object.defineProperty.
147 JS_PUBLIC_API
bool failCantDefineWindowNonConfigurable();
149 JS_PUBLIC_API
bool failBadArrayLength();
150 JS_PUBLIC_API
bool failBadIndex();
152 uint32_t failureCode() const {
154 return uint32_t(code_
);
158 * Report an error if necessary; return true to proceed and
159 * false if an error was reported.
161 * The precise rules are like this:
163 * - If ok(), then we succeeded. Do nothing and return true.
164 * - Otherwise, if |strict| is true, throw a TypeError and return false.
165 * - Otherwise, do nothing and return true.
167 bool checkStrictModeError(JSContext
* cx
, HandleObject obj
, HandleId id
,
169 if (ok() || !strict
) {
172 return reportError(cx
, obj
, id
);
176 * The same as checkStrictModeError(cx, id, strict), except the
177 * operation is not associated with a particular property id. This is
178 * used for [[PreventExtensions]] and [[SetPrototypeOf]]. failureCode()
179 * must not be an error that has "{0}" in the error message.
181 bool checkStrictModeError(JSContext
* cx
, HandleObject obj
, bool strict
) {
182 if (ok() || !strict
) {
185 return reportError(cx
, obj
);
188 /* Throw a TypeError. Call this only if !ok(). */
189 bool reportError(JSContext
* cx
, HandleObject obj
, HandleId id
);
192 * The same as reportError(cx, obj, id), except the operation is not
193 * associated with a particular property id.
195 bool reportError(JSContext
* cx
, HandleObject obj
);
197 // Convenience method. Return true if ok(); otherwise throw a TypeError
199 bool checkStrict(JSContext
* cx
, HandleObject obj
, HandleId id
) {
200 return checkStrictModeError(cx
, obj
, id
, true);
203 // Convenience method. The same as checkStrict(cx, obj, id), except the
204 // operation is not associated with a particular property id.
205 bool checkStrict(JSContext
* cx
, HandleObject obj
) {
206 return checkStrictModeError(cx
, obj
, true);
212 // JSClass operation signatures.
214 /** Add a property named by id to obj. */
215 typedef bool (*JSAddPropertyOp
)(JSContext
* cx
, JS::HandleObject obj
,
216 JS::HandleId id
, JS::HandleValue v
);
219 * Delete a property named by id in obj.
221 * If an error occurred, return false as per normal JSAPI error practice.
223 * If no error occurred, but the deletion attempt wasn't allowed (perhaps
224 * because the property was non-configurable), call result.fail() and
225 * return true. This will cause |delete obj[id]| to evaluate to false in
226 * non-strict mode code, and to throw a TypeError in strict mode code.
228 * If no error occurred and the deletion wasn't disallowed (this is *not* the
229 * same as saying that a deletion actually occurred -- deleting a non-existent
230 * property, or an inherited property, is allowed -- it's just pointless),
231 * call result.succeed() and return true.
233 typedef bool (*JSDeletePropertyOp
)(JSContext
* cx
, JS::HandleObject obj
,
234 JS::HandleId id
, JS::ObjectOpResult
& result
);
237 * The type of ObjectOps::enumerate. This callback overrides a portion of
238 * SpiderMonkey's default [[Enumerate]] internal method. When an ordinary object
239 * is enumerated, that object and each object on its prototype chain is tested
240 * for an enumerate op, and those ops are called in order. The properties each
241 * op adds to the 'properties' vector are added to the set of values the for-in
242 * loop will iterate over. All of this is nonstandard.
244 * An object is "enumerated" when it's the target of a for-in loop or
245 * JS_Enumerate(). The callback's job is to populate 'properties' with the
246 * object's property keys. If `enumerableOnly` is true, the callback should only
247 * add enumerable properties.
249 typedef bool (*JSNewEnumerateOp
)(JSContext
* cx
, JS::HandleObject obj
,
250 JS::MutableHandleIdVector properties
,
251 bool enumerableOnly
);
254 * The old-style JSClass.enumerate op should define all lazy properties not
255 * yet reflected in obj.
257 typedef bool (*JSEnumerateOp
)(JSContext
* cx
, JS::HandleObject obj
);
260 * The type of ObjectOps::funToString. This callback allows an object to
261 * provide a custom string to use when Function.prototype.toString is invoked on
262 * that object. A null return value means OOM.
264 typedef JSString
* (*JSFunToStringOp
)(JSContext
* cx
, JS::HandleObject obj
,
268 * Resolve a lazy property named by id in obj by defining it directly in obj.
269 * Lazy properties are those reflected from some peer native property space
270 * (e.g., the DOM attributes for a given node reflected as obj) on demand.
272 * JS looks for a property in an object, and if not found, tries to resolve
273 * the given id. *resolvedp should be set to true iff the property was defined
276 typedef bool (*JSResolveOp
)(JSContext
* cx
, JS::HandleObject obj
,
277 JS::HandleId id
, bool* resolvedp
);
280 * A class with a resolve hook can optionally have a mayResolve hook. This hook
281 * must have no side effects and must return true for a given id if the resolve
282 * hook may resolve this id. This is useful when we're doing a "pure" lookup: if
283 * mayResolve returns false, we know we don't have to call the effectful resolve
286 * maybeObj, if non-null, is the object on which we're doing the lookup. This
287 * can be nullptr: during JIT compilation we sometimes know the Class but not
290 typedef bool (*JSMayResolveOp
)(const JSAtomState
& names
, jsid id
,
294 * Finalize obj, which the garbage collector has determined to be unreachable
295 * from other live objects or from GC roots. Obviously, finalizers must never
296 * store a reference to obj.
298 typedef void (*JSFinalizeOp
)(JS::GCContext
* gcx
, JSObject
* obj
);
301 * Function type for trace operation of the class called to enumerate all
302 * traceable things reachable from obj's private data structure. For each such
303 * thing, a trace implementation must call JS::TraceEdge on the thing's
306 * JSTraceOp implementation can assume that no other threads mutates object
307 * state. It must not change state of the object or corresponding native
308 * structures. The only exception for this rule is the case when the embedding
309 * needs a tight integration with GC. In that case the embedding can check if
310 * the traversal is a part of the marking phase through calling
311 * JS_IsGCMarkingTracer and apply a special code like emptying caches or
312 * marking its native structures.
314 typedef void (*JSTraceOp
)(JSTracer
* trc
, JSObject
* obj
);
316 typedef size_t (*JSObjectMovedOp
)(JSObject
* obj
, JSObject
* old
);
320 /* Internal / friend API operation signatures. */
322 typedef bool (*LookupPropertyOp
)(JSContext
* cx
, JS::HandleObject obj
,
323 JS::HandleId id
, JS::MutableHandleObject objp
,
324 PropertyResult
* propp
);
325 typedef bool (*DefinePropertyOp
)(JSContext
* cx
, JS::HandleObject obj
,
327 JS::Handle
<JS::PropertyDescriptor
> desc
,
328 JS::ObjectOpResult
& result
);
329 typedef bool (*HasPropertyOp
)(JSContext
* cx
, JS::HandleObject obj
,
330 JS::HandleId id
, bool* foundp
);
331 typedef bool (*GetPropertyOp
)(JSContext
* cx
, JS::HandleObject obj
,
332 JS::HandleValue receiver
, JS::HandleId id
,
333 JS::MutableHandleValue vp
);
334 typedef bool (*SetPropertyOp
)(JSContext
* cx
, JS::HandleObject obj
,
335 JS::HandleId id
, JS::HandleValue v
,
336 JS::HandleValue receiver
,
337 JS::ObjectOpResult
& result
);
338 typedef bool (*GetOwnPropertyOp
)(
339 JSContext
* cx
, JS::HandleObject obj
, JS::HandleId id
,
340 JS::MutableHandle
<mozilla::Maybe
<JS::PropertyDescriptor
>> desc
);
341 typedef bool (*DeletePropertyOp
)(JSContext
* cx
, JS::HandleObject obj
,
342 JS::HandleId id
, JS::ObjectOpResult
& result
);
344 class JS_PUBLIC_API ElementAdder
{
347 // Check if the element exists before performing the Get and preserve
349 CheckHasElemPreserveHoles
,
351 // Perform a Get operation, like obj[index] in JS.
356 // Only one of these is used.
357 JS::RootedObject resObj_
;
364 GetBehavior getBehavior_
;
367 ElementAdder(JSContext
* cx
, JSObject
* obj
, uint32_t length
,
368 GetBehavior behavior
)
375 getBehavior_(behavior
) {
377 ElementAdder(JSContext
* cx
, JS::Value
* vp
, uint32_t length
,
378 GetBehavior behavior
)
385 getBehavior_(behavior
) {
388 GetBehavior
getBehavior() const { return getBehavior_
; }
390 bool append(JSContext
* cx
, JS::HandleValue v
);
394 typedef bool (*GetElementsOp
)(JSContext
* cx
, JS::HandleObject obj
,
395 uint32_t begin
, uint32_t end
,
396 ElementAdder
* adder
);
398 /** Callback for the creation of constructor and prototype objects. */
399 typedef JSObject
* (*ClassObjectCreationOp
)(JSContext
* cx
, JSProtoKey key
);
402 * Callback for custom post-processing after class initialization via
405 typedef bool (*FinishClassInitOp
)(JSContext
* cx
, JS::HandleObject ctor
,
406 JS::HandleObject proto
);
408 const size_t JSCLASS_CACHED_PROTO_WIDTH
= 7;
410 struct MOZ_STATIC_CLASS ClassSpec
{
411 ClassObjectCreationOp createConstructor
;
412 ClassObjectCreationOp createPrototype
;
413 const JSFunctionSpec
* constructorFunctions
;
414 const JSPropertySpec
* constructorProperties
;
415 const JSFunctionSpec
* prototypeFunctions
;
416 const JSPropertySpec
* prototypeProperties
;
417 FinishClassInitOp finishInit
;
420 static const size_t ProtoKeyWidth
= JSCLASS_CACHED_PROTO_WIDTH
;
422 static const uintptr_t ProtoKeyMask
= (1 << ProtoKeyWidth
) - 1;
423 static const uintptr_t DontDefineConstructor
= 1 << ProtoKeyWidth
;
425 bool defined() const { return !!createConstructor
; }
427 // The ProtoKey this class inherits from.
428 JSProtoKey
inheritanceProtoKey() const {
429 MOZ_ASSERT(defined());
430 static_assert(JSProto_Null
== 0, "zeroed key must be null");
432 // Default: Inherit from Object.
433 if (!(flags
& ProtoKeyMask
)) {
434 return JSProto_Object
;
437 return JSProtoKey(flags
& ProtoKeyMask
);
440 bool shouldDefineConstructor() const {
441 MOZ_ASSERT(defined());
442 return !(flags
& DontDefineConstructor
);
446 struct MOZ_STATIC_CLASS ClassExtension
{
448 * Optional hook called when an object is moved by generational or
451 * There may exist weak pointers to an object that are not traced through
452 * when the normal trace APIs are used, for example objects in the wrapper
453 * cache. This hook allows these pointers to be updated.
455 * Note that this hook can be called before JS_NewObject() returns if a GC
456 * is triggered during construction of the object. This can happen for
457 * global objects for example.
459 * The function should return the difference between nursery bytes used and
460 * tenured bytes used, which may be nonzero e.g. if some nursery-allocated
461 * data beyond the actual GC thing is moved into malloced memory.
463 * This is used to compute the nursery promotion rate.
465 JSObjectMovedOp objectMovedOp
;
468 struct MOZ_STATIC_CLASS ObjectOps
{
469 LookupPropertyOp lookupProperty
;
470 DefinePropertyOp defineProperty
;
471 HasPropertyOp hasProperty
;
472 GetPropertyOp getProperty
;
473 SetPropertyOp setProperty
;
474 GetOwnPropertyOp getOwnPropertyDescriptor
;
475 DeletePropertyOp deleteProperty
;
476 GetElementsOp getElements
;
477 JSFunToStringOp funToString
;
482 static constexpr const js::ClassSpec
* JS_NULL_CLASS_SPEC
= nullptr;
483 static constexpr const js::ClassExtension
* JS_NULL_CLASS_EXT
= nullptr;
485 static constexpr const js::ObjectOps
* JS_NULL_OBJECT_OPS
= nullptr;
487 // Classes, objects, and properties.
489 // (1 << 0 is unused)
491 // Class's initialization code will call `SetNewObjectMetadata` itself.
492 static const uint32_t JSCLASS_DELAY_METADATA_BUILDER
= 1 << 1;
494 // Class is an XPCWrappedNative. WeakMaps use this to override the wrapper
495 // disposal mechanism.
496 static const uint32_t JSCLASS_IS_WRAPPED_NATIVE
= 1 << 2;
498 // First reserved slot is `PrivateValue(nsISupports*)` or `UndefinedValue`.
499 static constexpr uint32_t JSCLASS_SLOT0_IS_NSISUPPORTS
= 1 << 3;
502 static const uint32_t JSCLASS_IS_DOMJSCLASS
= 1 << 4;
504 // If wrapped by an xray wrapper, the builtin class's constructor won't be
505 // unwrapped and invoked. Instead, the constructor is resolved in the caller's
506 // compartment and invoked with a wrapped newTarget. The constructor has to
507 // detect and handle this situation. See PromiseConstructor for details.
508 static const uint32_t JSCLASS_HAS_XRAYED_CONSTRUCTOR
= 1 << 5;
510 // Objects of this class act like the value undefined, in some contexts.
511 static const uint32_t JSCLASS_EMULATES_UNDEFINED
= 1 << 6;
513 // Reserved for embeddings.
514 static const uint32_t JSCLASS_USERBIT1
= 1 << 7;
516 // To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
517 // JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where n
518 // is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1.
520 // Room for 8 flags below ...
521 static const uintptr_t JSCLASS_RESERVED_SLOTS_SHIFT
= 8;
522 // ... and 16 above this field.
523 static const uint32_t JSCLASS_RESERVED_SLOTS_WIDTH
= 8;
525 static const uint32_t JSCLASS_RESERVED_SLOTS_MASK
=
526 js::BitMask(JSCLASS_RESERVED_SLOTS_WIDTH
);
528 static constexpr uint32_t JSCLASS_HAS_RESERVED_SLOTS(uint32_t n
) {
529 return (n
& JSCLASS_RESERVED_SLOTS_MASK
) << JSCLASS_RESERVED_SLOTS_SHIFT
;
532 static constexpr uint32_t JSCLASS_HIGH_FLAGS_SHIFT
=
533 JSCLASS_RESERVED_SLOTS_SHIFT
+ JSCLASS_RESERVED_SLOTS_WIDTH
;
535 static const uint32_t JSCLASS_INTERNAL_FLAG1
=
536 1 << (JSCLASS_HIGH_FLAGS_SHIFT
+ 0);
537 static const uint32_t JSCLASS_IS_GLOBAL
= 1 << (JSCLASS_HIGH_FLAGS_SHIFT
+ 1);
538 static const uint32_t JSCLASS_INTERNAL_FLAG2
=
539 1 << (JSCLASS_HIGH_FLAGS_SHIFT
+ 2);
540 static const uint32_t JSCLASS_IS_PROXY
= 1 << (JSCLASS_HIGH_FLAGS_SHIFT
+ 3);
541 static const uint32_t JSCLASS_SKIP_NURSERY_FINALIZE
=
542 1 << (JSCLASS_HIGH_FLAGS_SHIFT
+ 4);
544 // Reserved for embeddings.
545 static const uint32_t JSCLASS_USERBIT2
= 1 << (JSCLASS_HIGH_FLAGS_SHIFT
+ 5);
546 static const uint32_t JSCLASS_USERBIT3
= 1 << (JSCLASS_HIGH_FLAGS_SHIFT
+ 6);
548 static const uint32_t JSCLASS_BACKGROUND_FINALIZE
=
549 1 << (JSCLASS_HIGH_FLAGS_SHIFT
+ 7);
550 static const uint32_t JSCLASS_FOREGROUND_FINALIZE
=
551 1 << (JSCLASS_HIGH_FLAGS_SHIFT
+ 8);
553 // Bits 25 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see
556 // ECMA-262 requires that most constructors used internally create objects
557 // with "the original Foo.prototype value" as their [[Prototype]] (__proto__)
558 // member initial value. The "original ... value" verbiage is there because
559 // in ECMA-262, global properties naming class objects are read/write and
560 // deleteable, for the most part.
562 // Implementing this efficiently requires that global objects have classes
563 // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
564 // previously allowed, but is now an ES5 violation and thus unsupported.
566 // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
567 // the beginning of every global object's slots for use by the
569 static const uint32_t JSCLASS_GLOBAL_APPLICATION_SLOTS
= 5;
570 static const uint32_t JSCLASS_GLOBAL_SLOT_COUNT
=
571 JSCLASS_GLOBAL_APPLICATION_SLOTS
+ 1;
573 static constexpr uint32_t JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(uint32_t n
) {
574 return JSCLASS_IS_GLOBAL
|
575 JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT
+ n
);
578 static constexpr uint32_t JSCLASS_GLOBAL_FLAGS
=
579 JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0);
581 // Fast access to the original value of each standard class's prototype.
582 static const uint32_t JSCLASS_CACHED_PROTO_SHIFT
= JSCLASS_HIGH_FLAGS_SHIFT
+ 9;
583 static const uint32_t JSCLASS_CACHED_PROTO_MASK
=
584 js::BitMask(js::JSCLASS_CACHED_PROTO_WIDTH
);
586 static_assert(JSProto_LIMIT
<= (JSCLASS_CACHED_PROTO_MASK
+ 1),
587 "JSProtoKey must not exceed the maximum cacheable proto-mask");
589 static constexpr uint32_t JSCLASS_HAS_CACHED_PROTO(JSProtoKey key
) {
590 return uint32_t(key
) << JSCLASS_CACHED_PROTO_SHIFT
;
593 struct MOZ_STATIC_CLASS JSClassOps
{
594 /* Function pointer members (may be null). */
595 JSAddPropertyOp addProperty
;
596 JSDeletePropertyOp delProperty
;
597 JSEnumerateOp enumerate
;
598 JSNewEnumerateOp newEnumerate
;
600 JSMayResolveOp mayResolve
;
601 JSFinalizeOp finalize
;
607 static constexpr const JSClassOps
* JS_NULL_CLASS_OPS
= nullptr;
609 struct alignas(js::gc::JSClassAlignBytes
) JSClass
{
612 const JSClassOps
* cOps
;
614 const js::ClassSpec
* spec
;
615 const js::ClassExtension
* ext
;
616 const js::ObjectOps
* oOps
;
620 JSAddPropertyOp
getAddProperty() const {
621 return cOps
? cOps
->addProperty
: nullptr;
623 JSDeletePropertyOp
getDelProperty() const {
624 return cOps
? cOps
->delProperty
: nullptr;
626 JSEnumerateOp
getEnumerate() const {
627 return cOps
? cOps
->enumerate
: nullptr;
629 JSNewEnumerateOp
getNewEnumerate() const {
630 return cOps
? cOps
->newEnumerate
: nullptr;
632 JSResolveOp
getResolve() const { return cOps
? cOps
->resolve
: nullptr; }
633 JSMayResolveOp
getMayResolve() const {
634 return cOps
? cOps
->mayResolve
: nullptr;
636 JSNative
getCall() const { return cOps
? cOps
->call
: nullptr; }
637 JSNative
getConstruct() const { return cOps
? cOps
->construct
: nullptr; }
639 bool hasFinalize() const { return cOps
&& cOps
->finalize
; }
640 bool hasTrace() const { return cOps
&& cOps
->trace
; }
642 bool isTrace(JSTraceOp trace
) const { return cOps
&& cOps
->trace
== trace
; }
644 // The special treatment of |finalize| and |trace| is necessary because if we
645 // assign either of those hooks to a local variable and then call it -- as is
646 // done with the other hooks -- the GC hazard analysis gets confused.
647 void doFinalize(JS::GCContext
* gcx
, JSObject
* obj
) const {
648 MOZ_ASSERT(cOps
&& cOps
->finalize
);
649 cOps
->finalize(gcx
, obj
);
651 void doTrace(JSTracer
* trc
, JSObject
* obj
) const {
652 MOZ_ASSERT(cOps
&& cOps
->trace
);
653 cOps
->trace(trc
, obj
);
657 * Objects of this class aren't native objects. They don't have Shapes that
658 * describe their properties and layout. Classes using this flag must
659 * provide their own property behavior, either by being proxy classes (do
660 * this) or by overriding all the ObjectOps except getElements
663 static const uint32_t NON_NATIVE
= JSCLASS_INTERNAL_FLAG2
;
665 // A JSObject created from a JSClass extends from one of:
666 // - js::NativeObject
669 // While it is possible to introduce new families of objects, it is strongly
670 // discouraged. The JITs would be entirely unable to optimize them and testing
671 // coverage is low. The existing NativeObject and ProxyObject are extremely
672 // flexible and are able to represent the entire Gecko embedding requirements.
674 // NOTE: Internal to SpiderMonkey, there is an experimental js::TypedObject
675 // object family for future WASM features.
676 bool isNativeObject() const { return !(flags
& NON_NATIVE
); }
677 bool isProxyObject() const { return flags
& JSCLASS_IS_PROXY
; }
679 bool emulatesUndefined() const { return flags
& JSCLASS_EMULATES_UNDEFINED
; }
681 bool isJSFunction() const {
682 return this == js::FunctionClassPtr
|| this == js::FunctionExtendedClassPtr
;
685 bool nonProxyCallable() const {
686 MOZ_ASSERT(!isProxyObject());
687 return isJSFunction() || getCall();
690 bool isGlobal() const { return flags
& JSCLASS_IS_GLOBAL
; }
692 bool isDOMClass() const { return flags
& JSCLASS_IS_DOMJSCLASS
; }
694 bool shouldDelayMetadataBuilder() const {
695 return flags
& JSCLASS_DELAY_METADATA_BUILDER
;
698 bool isWrappedNative() const { return flags
& JSCLASS_IS_WRAPPED_NATIVE
; }
700 bool slot0IsISupports() const { return flags
& JSCLASS_SLOT0_IS_NSISUPPORTS
; }
702 static size_t offsetOfFlags() { return offsetof(JSClass
, flags
); }
704 // Internal / friend API accessors:
706 bool specDefined() const { return spec
? spec
->defined() : false; }
707 JSProtoKey
specInheritanceProtoKey() const {
708 return spec
? spec
->inheritanceProtoKey() : JSProto_Null
;
710 bool specShouldDefineConstructor() const {
711 return spec
? spec
->shouldDefineConstructor() : true;
713 js::ClassObjectCreationOp
specCreateConstructorHook() const {
714 return spec
? spec
->createConstructor
: nullptr;
716 js::ClassObjectCreationOp
specCreatePrototypeHook() const {
717 return spec
? spec
->createPrototype
: nullptr;
719 const JSFunctionSpec
* specConstructorFunctions() const {
720 return spec
? spec
->constructorFunctions
: nullptr;
722 const JSPropertySpec
* specConstructorProperties() const {
723 return spec
? spec
->constructorProperties
: nullptr;
725 const JSFunctionSpec
* specPrototypeFunctions() const {
726 return spec
? spec
->prototypeFunctions
: nullptr;
728 const JSPropertySpec
* specPrototypeProperties() const {
729 return spec
? spec
->prototypeProperties
: nullptr;
731 js::FinishClassInitOp
specFinishInitHook() const {
732 return spec
? spec
->finishInit
: nullptr;
735 JSObjectMovedOp
extObjectMovedOp() const {
736 return ext
? ext
->objectMovedOp
: nullptr;
739 js::LookupPropertyOp
getOpsLookupProperty() const {
740 return oOps
? oOps
->lookupProperty
: nullptr;
742 js::DefinePropertyOp
getOpsDefineProperty() const {
743 return oOps
? oOps
->defineProperty
: nullptr;
745 js::HasPropertyOp
getOpsHasProperty() const {
746 return oOps
? oOps
->hasProperty
: nullptr;
748 js::GetPropertyOp
getOpsGetProperty() const {
749 return oOps
? oOps
->getProperty
: nullptr;
751 js::SetPropertyOp
getOpsSetProperty() const {
752 return oOps
? oOps
->setProperty
: nullptr;
754 js::GetOwnPropertyOp
getOpsGetOwnPropertyDescriptor() const {
755 return oOps
? oOps
->getOwnPropertyDescriptor
: nullptr;
757 js::DeletePropertyOp
getOpsDeleteProperty() const {
758 return oOps
? oOps
->deleteProperty
: nullptr;
760 js::GetElementsOp
getOpsGetElements() const {
761 return oOps
? oOps
->getElements
: nullptr;
763 JSFunToStringOp
getOpsFunToString() const {
764 return oOps
? oOps
->funToString
: nullptr;
768 static constexpr uint32_t JSCLASS_RESERVED_SLOTS(const JSClass
* clasp
) {
769 return (clasp
->flags
>> JSCLASS_RESERVED_SLOTS_SHIFT
) &
770 JSCLASS_RESERVED_SLOTS_MASK
;
773 static constexpr bool JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(const JSClass
* clasp
) {
774 return (clasp
->flags
& JSCLASS_IS_GLOBAL
) &&
775 JSCLASS_RESERVED_SLOTS(clasp
) >= JSCLASS_GLOBAL_SLOT_COUNT
;
778 static constexpr JSProtoKey
JSCLASS_CACHED_PROTO_KEY(const JSClass
* clasp
) {
779 return JSProtoKey((clasp
->flags
>> JSCLASS_CACHED_PROTO_SHIFT
) &
780 JSCLASS_CACHED_PROTO_MASK
);
786 * Enumeration describing possible values of the [[Class]] internal property
807 Function
, // Note: Only JSFunction objects.
809 #ifdef ENABLE_RECORD_TUPLE
814 /** None of the above. */
818 /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */
819 bool Unbox(JSContext
* cx
, JS::HandleObject obj
, JS::MutableHandleValue vp
);
821 // Classes with JSCLASS_SKIP_NURSERY_FINALIZE or Wrapper classes with
822 // CROSS_COMPARTMENT flags will not have their finalizer called if they are
823 // nursery allocated and not promoted to the tenured heap. The finalizers for
824 // these classes must do nothing except free data which was allocated via
825 // Nursery::allocateBuffer.
826 inline bool CanNurseryAllocateFinalizedClass(const JSClass
* const clasp
) {
827 MOZ_ASSERT(clasp
->hasFinalize());
828 return clasp
->flags
& JSCLASS_SKIP_NURSERY_FINALIZE
;
832 JS_PUBLIC_API
bool HasObjectMovedOp(JSObject
* obj
);
837 #endif /* js_Class_h */