Merge mozilla-central to autoland. a=merge CLOSED TREE
[gecko.git] / js / public / Class.h
blob566419858425ad453f4949b24657c913bcb54cca
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. */
9 #ifndef js_Class_h
10 #define js_Class_h
12 #include "mozilla/Attributes.h"
13 #include "mozilla/Maybe.h"
15 #include "jstypes.h"
17 #include "js/CallArgs.h"
18 #include "js/HeapAPI.h"
19 #include "js/Id.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.
29 struct JSAtomState;
30 struct JSFunctionSpec;
32 namespace js {
34 class PropertyResult;
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;
40 } // namespace js
42 namespace JS {
44 /**
45 * Per ES6, the [[DefineOwnProperty]] internal method has three different
46 * possible outcomes:
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.
64 * Typical usage:
66 * ObjectOpResult result;
67 * if (!DefineProperty(cx, obj, id, ..., result)) {
68 * return false;
69 * }
70 * if (!result) {
71 * return result.reportError(cx, obj, id);
72 * }
74 * Users don't have to call `result.report()`; another possible ending is:
76 * argv.rval().setBoolean(result.ok());
77 * return true;
79 class ObjectOpResult {
80 private:
81 /**
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.
90 uintptr_t code_;
92 public:
93 enum SpecialCodes : uintptr_t { OkCode = 0, Uninitialized = uintptr_t(-1) };
95 ObjectOpResult() : code_(Uninitialized) {}
97 /* Return true if succeed() was called. */
98 bool ok() const {
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. */
106 bool succeed() {
107 code_ = OkCode;
108 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);
125 code_ = msg;
126 return true;
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 {
153 MOZ_ASSERT(!ok());
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,
168 bool strict) {
169 if (ok() || !strict) {
170 return true;
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) {
183 return true;
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
198 // and return false.
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);
210 } // namespace JS
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,
265 bool isToSource);
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
274 * on |obj|.
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
284 * hook.
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
288 * the object.
290 typedef bool (*JSMayResolveOp)(const JSAtomState& names, jsid id,
291 JSObject* maybeObj);
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
304 * location.
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);
318 namespace js {
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,
326 JS::HandleId id,
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 {
345 public:
346 enum GetBehavior {
347 // Check if the element exists before performing the Get and preserve
348 // holes.
349 CheckHasElemPreserveHoles,
351 // Perform a Get operation, like obj[index] in JS.
352 GetElement
355 private:
356 // Only one of these is used.
357 JS::RootedObject resObj_;
358 JS::Value* vp_;
360 uint32_t index_;
361 #ifdef DEBUG
362 uint32_t length_;
363 #endif
364 GetBehavior getBehavior_;
366 public:
367 ElementAdder(JSContext* cx, JSObject* obj, uint32_t length,
368 GetBehavior behavior)
369 : resObj_(cx, obj),
370 vp_(nullptr),
371 index_(0),
372 #ifdef DEBUG
373 length_(length),
374 #endif
375 getBehavior_(behavior) {
377 ElementAdder(JSContext* cx, JS::Value* vp, uint32_t length,
378 GetBehavior behavior)
379 : resObj_(cx),
380 vp_(vp),
381 index_(0),
382 #ifdef DEBUG
383 length_(length),
384 #endif
385 getBehavior_(behavior) {
388 GetBehavior getBehavior() const { return getBehavior_; }
390 bool append(JSContext* cx, JS::HandleValue v);
391 void appendHole();
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
403 * ClassSpec.
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;
418 uintptr_t flags;
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
449 * compacting GC.
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;
480 } // namespace js
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;
501 // Objects are DOM.
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
554 // below.
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
568 // application.
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;
599 JSResolveOp resolve;
600 JSMayResolveOp mayResolve;
601 JSFinalizeOp finalize;
602 JSNative call;
603 JSNative construct;
604 JSTraceOp trace;
607 static constexpr const JSClassOps* JS_NULL_CLASS_OPS = nullptr;
609 struct alignas(js::gc::JSClassAlignBytes) JSClass {
610 const char* name;
611 uint32_t flags;
612 const JSClassOps* cOps;
614 const js::ClassSpec* spec;
615 const js::ClassExtension* ext;
616 const js::ObjectOps* oOps;
618 // Public accessors:
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
661 * (don't do this).
663 static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
665 // A JSObject created from a JSClass extends from one of:
666 // - js::NativeObject
667 // - js::ProxyObject
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);
783 namespace js {
786 * Enumeration describing possible values of the [[Class]] internal property
787 * value of objects.
789 enum class ESClass {
790 Object,
791 Array,
792 Number,
793 String,
794 Boolean,
795 RegExp,
796 ArrayBuffer,
797 SharedArrayBuffer,
798 Date,
799 Set,
800 Map,
801 Promise,
802 MapIterator,
803 SetIterator,
804 Arguments,
805 Error,
806 BigInt,
807 Function, // Note: Only JSFunction objects.
809 #ifdef ENABLE_RECORD_TUPLE
810 Record,
811 Tuple,
812 #endif
814 /** None of the above. */
815 Other
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;
831 #ifdef DEBUG
832 JS_PUBLIC_API bool HasObjectMovedOp(JSObject* obj);
833 #endif
835 } /* namespace js */
837 #endif /* js_Class_h */