tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Class.h (30119B)


      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/. */
      6 
      7 /* JSClass definition and its component types, plus related interfaces. */
      8 
      9 #ifndef js_Class_h
     10 #define js_Class_h
     11 
     12 #include "mozilla/Attributes.h"
     13 #include "mozilla/Maybe.h"
     14 
     15 #include "jstypes.h"
     16 
     17 #include "js/CallArgs.h"
     18 #include "js/HeapAPI.h"
     19 #include "js/Id.h"
     20 #include "js/TypeDecls.h"
     21 
     22 /*
     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.
     27 */
     28 
     29 struct JSAtomState;
     30 struct JSFunctionSpec;
     31 
     32 namespace js {
     33 
     34 class PropertyResult;
     35 
     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;
     39 
     40 }  // namespace js
     41 
     42 namespace JS {
     43 
     44 /**
     45 * Per ES6, the [[DefineOwnProperty]] internal method has three different
     46 * possible outcomes:
     47 *
     48 * -   It can throw an exception (which we indicate by returning false).
     49 *
     50 * -   It can return true, indicating unvarnished success.
     51 *
     52 * -   It can return false, indicating "strict failure". The property could
     53 *     not be defined. It's an error, but no exception was thrown.
     54 *
     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]].)
     58 *
     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.
     63 *
     64 * Typical usage:
     65 *
     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 *     }
     73 *
     74 * Users don't have to call `result.report()`; another possible ending is:
     75 *
     76 *     argv.rval().setBoolean(result.ok());
     77 *     return true;
     78 */
     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.
     85   *
     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.
     89   */
     90  uintptr_t code_;
     91 
     92 public:
     93  enum SpecialCodes : uintptr_t { OkCode = 0, Uninitialized = uintptr_t(-1) };
     94 
     95  ObjectOpResult() : code_(Uninitialized) {}
     96 
     97  /* Return true if succeed() was called. */
     98  bool ok() const {
     99    MOZ_ASSERT(code_ != Uninitialized);
    100    return code_ == OkCode;
    101  }
    102 
    103  explicit operator bool() const { return ok(); }
    104 
    105  /* Set this ObjectOpResult to true and return true. */
    106  bool succeed() {
    107    code_ = OkCode;
    108    return true;
    109  }
    110 
    111  /*
    112   * Set this ObjectOpResult to false with an error code.
    113   *
    114   * Always returns true, as a convenience. Typical usage will be:
    115   *
    116   *     if (funny condition) {
    117   *         return result.fail(JSMSG_CANT_DO_THE_THINGS);
    118   *     }
    119   *
    120   * The true return value indicates that no exception is pending, and it
    121   * would be OK to ignore the failure and continue.
    122   */
    123  bool fail(uint32_t msg) {
    124    MOZ_ASSERT(msg != OkCode);
    125    code_ = msg;
    126    return true;
    127  }
    128 
    129  JS_PUBLIC_API bool failCantRedefineProp();
    130  JS_PUBLIC_API bool failReadOnly();
    131  JS_PUBLIC_API bool failGetterOnly();
    132  JS_PUBLIC_API bool failCantDelete();
    133 
    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();
    145 
    146  // Careful: This case has special handling in Object.defineProperty.
    147  JS_PUBLIC_API bool failCantDefineWindowNonConfigurable();
    148 
    149  JS_PUBLIC_API bool failBadArrayLength();
    150  JS_PUBLIC_API bool failBadIndex();
    151 
    152  uint32_t failureCode() const {
    153    MOZ_ASSERT(!ok());
    154    return uint32_t(code_);
    155  }
    156 
    157  /*
    158   * Report an error if necessary; return true to proceed and
    159   * false if an error was reported.
    160   *
    161   * The precise rules are like this:
    162   *
    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.
    166   */
    167  bool checkStrictModeError(JSContext* cx, HandleObject obj, HandleId id,
    168                            bool strict) {
    169    if (ok() || !strict) {
    170      return true;
    171    }
    172    return reportError(cx, obj, id);
    173  }
    174 
    175  /*
    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.
    180   */
    181  bool checkStrictModeError(JSContext* cx, HandleObject obj, bool strict) {
    182    if (ok() || !strict) {
    183      return true;
    184    }
    185    return reportError(cx, obj);
    186  }
    187 
    188  /* Throw a TypeError. Call this only if !ok(). */
    189  bool reportError(JSContext* cx, HandleObject obj, HandleId id);
    190 
    191  /*
    192   * The same as reportError(cx, obj, id), except the operation is not
    193   * associated with a particular property id.
    194   */
    195  bool reportError(JSContext* cx, HandleObject obj);
    196 
    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);
    201  }
    202 
    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);
    207  }
    208 };
    209 
    210 }  // namespace JS
    211 
    212 // JSClass operation signatures.
    213 
    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);
    217 
    218 /**
    219 * Delete a property named by id in obj.
    220 *
    221 * If an error occurred, return false as per normal JSAPI error practice.
    222 *
    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.
    227 *
    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.
    232 */
    233 typedef bool (*JSDeletePropertyOp)(JSContext* cx, JS::HandleObject obj,
    234                                   JS::HandleId id, JS::ObjectOpResult& result);
    235 
    236 /**
    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.
    243 *
    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.
    248 */
    249 typedef bool (*JSNewEnumerateOp)(JSContext* cx, JS::HandleObject obj,
    250                                 JS::MutableHandleIdVector properties,
    251                                 bool enumerableOnly);
    252 
    253 /**
    254 * The old-style JSClass.enumerate op should define all lazy properties not
    255 * yet reflected in obj.
    256 */
    257 typedef bool (*JSEnumerateOp)(JSContext* cx, JS::HandleObject obj);
    258 
    259 /**
    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.
    263 */
    264 typedef JSString* (*JSFunToStringOp)(JSContext* cx, JS::HandleObject obj,
    265                                     bool isToSource);
    266 
    267 /**
    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.
    271 *
    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|.
    275 *
    276 * See JS::dbg::ShouldAvoidSideEffects in Debug.h if this function has any
    277 * other side-effect than just resolving the property.
    278 */
    279 typedef bool (*JSResolveOp)(JSContext* cx, JS::HandleObject obj,
    280                            JS::HandleId id, bool* resolvedp);
    281 
    282 /**
    283 * A class with a resolve hook can optionally have a mayResolve hook. This hook
    284 * must have no side effects and must return true for a given id if the resolve
    285 * hook may resolve this id. This is useful when we're doing a "pure" lookup: if
    286 * mayResolve returns false, we know we don't have to call the effectful resolve
    287 * hook.
    288 *
    289 * maybeObj, if non-null, is the object on which we're doing the lookup. This
    290 * can be nullptr: during JIT compilation we sometimes know the Class but not
    291 * the object.
    292 */
    293 typedef bool (*JSMayResolveOp)(const JSAtomState& names, jsid id,
    294                               JSObject* maybeObj);
    295 
    296 /**
    297 * Finalize obj, which the garbage collector has determined to be unreachable
    298 * from other live objects or from GC roots.  Obviously, finalizers must never
    299 * store a reference to obj.
    300 */
    301 typedef void (*JSFinalizeOp)(JS::GCContext* gcx, JSObject* obj);
    302 
    303 /**
    304 * Function type for trace operation of the class called to enumerate all
    305 * traceable things reachable from obj's private data structure. For each such
    306 * thing, a trace implementation must call JS::TraceEdge on the thing's
    307 * location.
    308 *
    309 * JSTraceOp implementation can assume that no other threads mutates object
    310 * state. It must not change state of the object or corresponding native
    311 * structures. The only exception for this rule is the case when the embedding
    312 * needs a tight integration with GC. In that case the embedding can check if
    313 * the traversal is a part of the marking phase through calling
    314 * JS_IsGCMarkingTracer and apply a special code like emptying caches or
    315 * marking its native structures.
    316 */
    317 typedef void (*JSTraceOp)(JSTracer* trc, JSObject* obj);
    318 
    319 typedef size_t (*JSObjectMovedOp)(JSObject* obj, JSObject* old);
    320 
    321 namespace js {
    322 
    323 /* Internal / friend API operation signatures. */
    324 
    325 typedef bool (*LookupPropertyOp)(JSContext* cx, JS::HandleObject obj,
    326                                 JS::HandleId id, JS::MutableHandleObject objp,
    327                                 PropertyResult* propp);
    328 typedef bool (*DefinePropertyOp)(JSContext* cx, JS::HandleObject obj,
    329                                 JS::HandleId id,
    330                                 JS::Handle<JS::PropertyDescriptor> desc,
    331                                 JS::ObjectOpResult& result);
    332 typedef bool (*HasPropertyOp)(JSContext* cx, JS::HandleObject obj,
    333                              JS::HandleId id, bool* foundp);
    334 typedef bool (*GetPropertyOp)(JSContext* cx, JS::HandleObject obj,
    335                              JS::HandleValue receiver, JS::HandleId id,
    336                              JS::MutableHandleValue vp);
    337 typedef bool (*SetPropertyOp)(JSContext* cx, JS::HandleObject obj,
    338                              JS::HandleId id, JS::HandleValue v,
    339                              JS::HandleValue receiver,
    340                              JS::ObjectOpResult& result);
    341 typedef bool (*GetOwnPropertyOp)(
    342    JSContext* cx, JS::HandleObject obj, JS::HandleId id,
    343    JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc);
    344 typedef bool (*DeletePropertyOp)(JSContext* cx, JS::HandleObject obj,
    345                                 JS::HandleId id, JS::ObjectOpResult& result);
    346 
    347 class JS_PUBLIC_API ElementAdder {
    348 public:
    349  enum GetBehavior {
    350    // Check if the element exists before performing the Get and preserve
    351    // holes.
    352    CheckHasElemPreserveHoles,
    353 
    354    // Perform a Get operation, like obj[index] in JS.
    355    GetElement
    356  };
    357 
    358 private:
    359  // Only one of these is used.
    360  JS::RootedObject resObj_;
    361  JS::Value* vp_;
    362 
    363  uint32_t index_;
    364 #ifdef DEBUG
    365  uint32_t length_;
    366 #endif
    367  GetBehavior getBehavior_;
    368 
    369 public:
    370  ElementAdder(JSContext* cx, JSObject* obj, uint32_t length,
    371               GetBehavior behavior)
    372      : resObj_(cx, obj),
    373        vp_(nullptr),
    374        index_(0),
    375 #ifdef DEBUG
    376        length_(length),
    377 #endif
    378        getBehavior_(behavior) {
    379  }
    380  ElementAdder(JSContext* cx, JS::Value* vp, uint32_t length,
    381               GetBehavior behavior)
    382      : resObj_(cx),
    383        vp_(vp),
    384        index_(0),
    385 #ifdef DEBUG
    386        length_(length),
    387 #endif
    388        getBehavior_(behavior) {
    389  }
    390 
    391  GetBehavior getBehavior() const { return getBehavior_; }
    392 
    393  bool append(JSContext* cx, JS::HandleValue v);
    394  void appendHole();
    395 };
    396 
    397 typedef bool (*GetElementsOp)(JSContext* cx, JS::HandleObject obj,
    398                              uint32_t begin, uint32_t end,
    399                              ElementAdder* adder);
    400 
    401 /** Callback for the creation of constructor and prototype objects. */
    402 typedef JSObject* (*ClassObjectCreationOp)(JSContext* cx, JSProtoKey key);
    403 
    404 /**
    405 * Callback for custom post-processing after class initialization via
    406 * ClassSpec.
    407 */
    408 typedef bool (*FinishClassInitOp)(JSContext* cx, JS::HandleObject ctor,
    409                                  JS::HandleObject proto);
    410 
    411 const size_t JSCLASS_CACHED_PROTO_WIDTH = 7;
    412 
    413 struct MOZ_STATIC_CLASS ClassSpec {
    414  ClassObjectCreationOp createConstructor;
    415  ClassObjectCreationOp createPrototype;
    416  const JSFunctionSpec* constructorFunctions;
    417  const JSPropertySpec* constructorProperties;
    418  const JSFunctionSpec* prototypeFunctions;
    419  const JSPropertySpec* prototypeProperties;
    420  FinishClassInitOp finishInit;
    421  uintptr_t flags;
    422 
    423  static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH;
    424 
    425  static const uintptr_t ProtoKeyMask = (1 << ProtoKeyWidth) - 1;
    426  static const uintptr_t DontDefineConstructor = 1 << ProtoKeyWidth;
    427 
    428  bool defined() const { return !!createConstructor; }
    429 
    430  // The ProtoKey this class inherits from.
    431  JSProtoKey inheritanceProtoKey() const {
    432    MOZ_ASSERT(defined());
    433    static_assert(JSProto_Null == 0, "zeroed key must be null");
    434 
    435    // Default: Inherit from Object.
    436    if (!(flags & ProtoKeyMask)) {
    437      return JSProto_Object;
    438    }
    439 
    440    return JSProtoKey(flags & ProtoKeyMask);
    441  }
    442 
    443  bool shouldDefineConstructor() const {
    444    MOZ_ASSERT(defined());
    445    return !(flags & DontDefineConstructor);
    446  }
    447 };
    448 
    449 struct MOZ_STATIC_CLASS ClassExtension {
    450  /**
    451   * Optional hook called when an object is moved by generational or
    452   * compacting GC.
    453   *
    454   * There may exist weak pointers to an object that are not traced through
    455   * when the normal trace APIs are used, for example objects in the wrapper
    456   * cache. This hook allows these pointers to be updated.
    457   *
    458   * Note that this hook can be called before JS_NewObject() returns if a GC
    459   * is triggered during construction of the object. This can happen for
    460   * global objects for example.
    461   *
    462   * The function should return the difference between nursery bytes used and
    463   * tenured bytes used, which may be nonzero e.g. if some nursery-allocated
    464   * data beyond the actual GC thing is moved into malloced memory.
    465   *
    466   * This is used to compute the nursery promotion rate.
    467   */
    468  JSObjectMovedOp objectMovedOp;
    469 };
    470 
    471 struct MOZ_STATIC_CLASS ObjectOps {
    472  LookupPropertyOp lookupProperty;
    473  DefinePropertyOp defineProperty;
    474  HasPropertyOp hasProperty;
    475  GetPropertyOp getProperty;
    476  SetPropertyOp setProperty;
    477  GetOwnPropertyOp getOwnPropertyDescriptor;
    478  DeletePropertyOp deleteProperty;
    479  GetElementsOp getElements;
    480  JSFunToStringOp funToString;
    481 };
    482 
    483 }  // namespace js
    484 
    485 static constexpr const js::ClassSpec* JS_NULL_CLASS_SPEC = nullptr;
    486 static constexpr const js::ClassExtension* JS_NULL_CLASS_EXT = nullptr;
    487 
    488 static constexpr const js::ObjectOps* JS_NULL_OBJECT_OPS = nullptr;
    489 
    490 // Classes, objects, and properties.
    491 
    492 // Must call a callback when the first property is added to an object of this
    493 // class. If this is set, the object must store a pointer at
    494 // JS_OBJECT_WRAPPER_SLOT to the C++ wrapper as a PrivateValue or
    495 // UndefinedValue() if the object does not have a wrapper.
    496 static const uint32_t JSCLASS_PRESERVES_WRAPPER = 1 << 0;
    497 
    498 // Class's initialization code will call `SetNewObjectMetadata` itself.
    499 static const uint32_t JSCLASS_DELAY_METADATA_BUILDER = 1 << 1;
    500 
    501 // Class is an XPCWrappedNative. WeakMaps use this to override the wrapper
    502 // disposal mechanism.
    503 static const uint32_t JSCLASS_IS_WRAPPED_NATIVE = 1 << 2;
    504 
    505 // First reserved slot is `PrivateValue(nsISupports*)` or `UndefinedValue`.
    506 static constexpr uint32_t JSCLASS_SLOT0_IS_NSISUPPORTS = 1 << 3;
    507 
    508 // Objects are DOM.
    509 static const uint32_t JSCLASS_IS_DOMJSCLASS = 1 << 4;
    510 
    511 // If wrapped by an xray wrapper, the builtin class's constructor won't be
    512 // unwrapped and invoked. Instead, the constructor is resolved in the caller's
    513 // compartment and invoked with a wrapped newTarget. The constructor has to
    514 // detect and handle this situation. See PromiseConstructor for details.
    515 static const uint32_t JSCLASS_HAS_XRAYED_CONSTRUCTOR = 1 << 5;
    516 
    517 // Objects of this class act like the value undefined, in some contexts.
    518 static const uint32_t JSCLASS_EMULATES_UNDEFINED = 1 << 6;
    519 
    520 // Reserved for embeddings.
    521 static const uint32_t JSCLASS_USERBIT1 = 1 << 7;
    522 
    523 // To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
    524 // JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where n
    525 // is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1.
    526 
    527 // Room for 8 flags below ...
    528 static const uintptr_t JSCLASS_RESERVED_SLOTS_SHIFT = 8;
    529 // ... and 16 above this field.
    530 static const uint32_t JSCLASS_RESERVED_SLOTS_WIDTH = 8;
    531 
    532 static const uint32_t JSCLASS_RESERVED_SLOTS_MASK =
    533    js::BitMask(JSCLASS_RESERVED_SLOTS_WIDTH);
    534 
    535 static constexpr uint32_t JSCLASS_HAS_RESERVED_SLOTS(uint32_t n) {
    536  return (n & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT;
    537 }
    538 
    539 static constexpr uint32_t JSCLASS_HIGH_FLAGS_SHIFT =
    540    JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH;
    541 
    542 static const uint32_t JSCLASS_INTERNAL_FLAG1 =
    543    1 << (JSCLASS_HIGH_FLAGS_SHIFT + 0);
    544 static const uint32_t JSCLASS_IS_GLOBAL = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1);
    545 static const uint32_t JSCLASS_INTERNAL_FLAG2 =
    546    1 << (JSCLASS_HIGH_FLAGS_SHIFT + 2);
    547 static const uint32_t JSCLASS_IS_PROXY = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 3);
    548 static const uint32_t JSCLASS_SKIP_NURSERY_FINALIZE =
    549    1 << (JSCLASS_HIGH_FLAGS_SHIFT + 4);
    550 
    551 // Reserved for embeddings.
    552 static const uint32_t JSCLASS_USERBIT2 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 5);
    553 static const uint32_t JSCLASS_USERBIT3 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 6);
    554 
    555 static const uint32_t JSCLASS_BACKGROUND_FINALIZE =
    556    1 << (JSCLASS_HIGH_FLAGS_SHIFT + 7);
    557 static const uint32_t JSCLASS_FOREGROUND_FINALIZE =
    558    1 << (JSCLASS_HIGH_FLAGS_SHIFT + 8);
    559 
    560 // Bits 25 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see
    561 // below.
    562 
    563 // ECMA-262 requires that most constructors used internally create objects
    564 // with "the original Foo.prototype value" as their [[Prototype]] (__proto__)
    565 // member initial value.  The "original ... value" verbiage is there because
    566 // in ECMA-262, global properties naming class objects are read/write and
    567 // deleteable, for the most part.
    568 //
    569 // Implementing this efficiently requires that global objects have classes
    570 // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
    571 // previously allowed, but is now an ES5 violation and thus unsupported.
    572 //
    573 // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
    574 // the beginning of every global object's slots for use by the
    575 // application.
    576 static const uint32_t JSCLASS_GLOBAL_APPLICATION_SLOTS = 5;
    577 static const uint32_t JSCLASS_GLOBAL_SLOT_COUNT =
    578    JSCLASS_GLOBAL_APPLICATION_SLOTS + 1;
    579 
    580 static constexpr uint32_t JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(uint32_t n) {
    581  return JSCLASS_IS_GLOBAL |
    582         JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + n);
    583 }
    584 
    585 static constexpr uint32_t JSCLASS_GLOBAL_FLAGS =
    586    JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0);
    587 
    588 // Fast access to the original value of each standard class's prototype.
    589 static const uint32_t JSCLASS_CACHED_PROTO_SHIFT = JSCLASS_HIGH_FLAGS_SHIFT + 9;
    590 static const uint32_t JSCLASS_CACHED_PROTO_MASK =
    591    js::BitMask(js::JSCLASS_CACHED_PROTO_WIDTH);
    592 
    593 static_assert(JSProto_LIMIT <= (JSCLASS_CACHED_PROTO_MASK + 1),
    594              "JSProtoKey must not exceed the maximum cacheable proto-mask");
    595 
    596 static constexpr uint32_t JSCLASS_HAS_CACHED_PROTO(JSProtoKey key) {
    597  return uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT;
    598 }
    599 
    600 // See JSCLASS_PRESERVES_WRAPPER.
    601 static constexpr size_t JS_OBJECT_WRAPPER_SLOT = 0;
    602 
    603 struct MOZ_STATIC_CLASS JSClassOps {
    604  /* Function pointer members (may be null). */
    605  JSAddPropertyOp addProperty;
    606  JSDeletePropertyOp delProperty;
    607  JSEnumerateOp enumerate;
    608  JSNewEnumerateOp newEnumerate;
    609  JSResolveOp resolve;
    610  JSMayResolveOp mayResolve;
    611  JSFinalizeOp finalize;
    612  JSNative call;
    613  JSNative construct;
    614  JSTraceOp trace;
    615 };
    616 
    617 static constexpr const JSClassOps* JS_NULL_CLASS_OPS = nullptr;
    618 
    619 // Note: This is a MOZ_STATIC_CLASS, as having a non-static JSClass
    620 // can lead to bizarre behaviour, however the annotation
    621 // is at the bottom to handle some incompatibility with GCC
    622 // annotation processing.
    623 struct alignas(js::gc::JSClassAlignBytes) JSClass {
    624  const char* name;
    625  uint32_t flags;
    626  const JSClassOps* cOps;
    627 
    628  const js::ClassSpec* spec;
    629  const js::ClassExtension* ext;
    630  const js::ObjectOps* oOps;
    631 
    632  // Public accessors:
    633 
    634  JSAddPropertyOp getAddProperty() const {
    635    return cOps ? cOps->addProperty : nullptr;
    636  }
    637  JSDeletePropertyOp getDelProperty() const {
    638    return cOps ? cOps->delProperty : nullptr;
    639  }
    640  JSEnumerateOp getEnumerate() const {
    641    return cOps ? cOps->enumerate : nullptr;
    642  }
    643  JSNewEnumerateOp getNewEnumerate() const {
    644    return cOps ? cOps->newEnumerate : nullptr;
    645  }
    646  JSResolveOp getResolve() const { return cOps ? cOps->resolve : nullptr; }
    647  JSMayResolveOp getMayResolve() const {
    648    return cOps ? cOps->mayResolve : nullptr;
    649  }
    650  JSNative getCall() const { return cOps ? cOps->call : nullptr; }
    651  JSNative getConstruct() const { return cOps ? cOps->construct : nullptr; }
    652 
    653  bool hasFinalize() const { return cOps && cOps->finalize; }
    654  bool hasTrace() const { return cOps && cOps->trace; }
    655 
    656  bool isTrace(JSTraceOp trace) const { return cOps && cOps->trace == trace; }
    657 
    658  // The special treatment of |finalize| and |trace| is necessary because if we
    659  // assign either of those hooks to a local variable and then call it -- as is
    660  // done with the other hooks -- the GC hazard analysis gets confused.
    661  void doFinalize(JS::GCContext* gcx, JSObject* obj) const {
    662    MOZ_ASSERT(cOps && cOps->finalize);
    663    cOps->finalize(gcx, obj);
    664  }
    665  void doTrace(JSTracer* trc, JSObject* obj) const {
    666    MOZ_ASSERT(cOps && cOps->trace);
    667    cOps->trace(trc, obj);
    668  }
    669 
    670  /*
    671   * Objects of this class aren't native objects. They don't have Shapes that
    672   * describe their properties and layout. Classes using this flag must
    673   * provide their own property behavior, either by being proxy classes (do
    674   * this) or by overriding all the ObjectOps except getElements
    675   * (don't do this).
    676   */
    677  static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
    678 
    679  // A JSObject created from a JSClass extends from one of:
    680  //  - js::NativeObject
    681  //  - js::ProxyObject
    682  //
    683  // While it is possible to introduce new families of objects, it is strongly
    684  // discouraged. The JITs would be entirely unable to optimize them and testing
    685  // coverage is low. The existing NativeObject and ProxyObject are extremely
    686  // flexible and are able to represent the entire Gecko embedding requirements.
    687  //
    688  // NOTE: Internal to SpiderMonkey, there is an experimental js::TypedObject
    689  //       object family for future WASM features.
    690  bool isNativeObject() const { return !(flags & NON_NATIVE); }
    691  bool isProxyObject() const { return flags & JSCLASS_IS_PROXY; }
    692 
    693  bool emulatesUndefined() const { return flags & JSCLASS_EMULATES_UNDEFINED; }
    694 
    695  bool isJSFunction() const {
    696    return this == js::FunctionClassPtr || this == js::FunctionExtendedClassPtr;
    697  }
    698 
    699  bool nonProxyCallable() const {
    700    MOZ_ASSERT(!isProxyObject());
    701    return isJSFunction() || getCall();
    702  }
    703 
    704  bool isGlobal() const { return flags & JSCLASS_IS_GLOBAL; }
    705 
    706  bool isDOMClass() const { return flags & JSCLASS_IS_DOMJSCLASS; }
    707 
    708  bool shouldDelayMetadataBuilder() const {
    709    return flags & JSCLASS_DELAY_METADATA_BUILDER;
    710  }
    711 
    712  bool isWrappedNative() const { return flags & JSCLASS_IS_WRAPPED_NATIVE; }
    713 
    714  bool slot0IsISupports() const { return flags & JSCLASS_SLOT0_IS_NSISUPPORTS; }
    715 
    716  bool preservesWrapper() const { return flags & JSCLASS_PRESERVES_WRAPPER; }
    717 
    718  static size_t offsetOfFlags() { return offsetof(JSClass, flags); }
    719 
    720  // Internal / friend API accessors:
    721 
    722  bool specDefined() const { return spec ? spec->defined() : false; }
    723  JSProtoKey specInheritanceProtoKey() const {
    724    return spec ? spec->inheritanceProtoKey() : JSProto_Null;
    725  }
    726  bool specShouldDefineConstructor() const {
    727    return spec ? spec->shouldDefineConstructor() : true;
    728  }
    729  js::ClassObjectCreationOp specCreateConstructorHook() const {
    730    return spec ? spec->createConstructor : nullptr;
    731  }
    732  js::ClassObjectCreationOp specCreatePrototypeHook() const {
    733    return spec ? spec->createPrototype : nullptr;
    734  }
    735  const JSFunctionSpec* specConstructorFunctions() const {
    736    return spec ? spec->constructorFunctions : nullptr;
    737  }
    738  const JSPropertySpec* specConstructorProperties() const {
    739    return spec ? spec->constructorProperties : nullptr;
    740  }
    741  const JSFunctionSpec* specPrototypeFunctions() const {
    742    return spec ? spec->prototypeFunctions : nullptr;
    743  }
    744  const JSPropertySpec* specPrototypeProperties() const {
    745    return spec ? spec->prototypeProperties : nullptr;
    746  }
    747  js::FinishClassInitOp specFinishInitHook() const {
    748    return spec ? spec->finishInit : nullptr;
    749  }
    750 
    751  JSObjectMovedOp extObjectMovedOp() const {
    752    return ext ? ext->objectMovedOp : nullptr;
    753  }
    754 
    755  js::LookupPropertyOp getOpsLookupProperty() const {
    756    return oOps ? oOps->lookupProperty : nullptr;
    757  }
    758  js::DefinePropertyOp getOpsDefineProperty() const {
    759    return oOps ? oOps->defineProperty : nullptr;
    760  }
    761  js::HasPropertyOp getOpsHasProperty() const {
    762    return oOps ? oOps->hasProperty : nullptr;
    763  }
    764  js::GetPropertyOp getOpsGetProperty() const {
    765    return oOps ? oOps->getProperty : nullptr;
    766  }
    767  js::SetPropertyOp getOpsSetProperty() const {
    768    return oOps ? oOps->setProperty : nullptr;
    769  }
    770  js::GetOwnPropertyOp getOpsGetOwnPropertyDescriptor() const {
    771    return oOps ? oOps->getOwnPropertyDescriptor : nullptr;
    772  }
    773  js::DeletePropertyOp getOpsDeleteProperty() const {
    774    return oOps ? oOps->deleteProperty : nullptr;
    775  }
    776  js::GetElementsOp getOpsGetElements() const {
    777    return oOps ? oOps->getElements : nullptr;
    778  }
    779  JSFunToStringOp getOpsFunToString() const {
    780    return oOps ? oOps->funToString : nullptr;
    781  }
    782 } MOZ_STATIC_CLASS;
    783 
    784 static constexpr uint32_t JSCLASS_RESERVED_SLOTS(const JSClass* clasp) {
    785  return (clasp->flags >> JSCLASS_RESERVED_SLOTS_SHIFT) &
    786         JSCLASS_RESERVED_SLOTS_MASK;
    787 }
    788 
    789 static constexpr bool JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(const JSClass* clasp) {
    790  return (clasp->flags & JSCLASS_IS_GLOBAL) &&
    791         JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT;
    792 }
    793 
    794 static constexpr JSProtoKey JSCLASS_CACHED_PROTO_KEY(const JSClass* clasp) {
    795  return JSProtoKey((clasp->flags >> JSCLASS_CACHED_PROTO_SHIFT) &
    796                    JSCLASS_CACHED_PROTO_MASK);
    797 }
    798 
    799 namespace js {
    800 
    801 /**
    802 * Enumeration describing possible values of the [[Class]] internal property
    803 * value of objects.
    804 */
    805 enum class ESClass {
    806  Object,
    807  Array,
    808  Number,
    809  String,
    810  Boolean,
    811  RegExp,
    812  ArrayBuffer,
    813  SharedArrayBuffer,
    814  Date,
    815  Set,
    816  Map,
    817  Promise,
    818  MapIterator,
    819  SetIterator,
    820  Arguments,
    821  Error,
    822  BigInt,
    823  Function,  // Note: Only JSFunction objects.
    824 
    825  /** None of the above. */
    826  Other
    827 };
    828 
    829 /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */
    830 bool Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp);
    831 
    832 // Classes with JSCLASS_SKIP_NURSERY_FINALIZE or Wrapper classes with
    833 // CROSS_COMPARTMENT flags will not have their finalizer called if they are
    834 // nursery allocated and not promoted to the tenured heap. The finalizers for
    835 // these classes must do nothing except free data which was allocated via
    836 // Nursery::allocateBuffer.
    837 inline bool CanNurseryAllocateFinalizedClass(const JSClass* const clasp) {
    838  MOZ_ASSERT(clasp->hasFinalize());
    839  return clasp->flags & JSCLASS_SKIP_NURSERY_FINALIZE;
    840 }
    841 
    842 #ifdef DEBUG
    843 JS_PUBLIC_API bool HasObjectMovedOp(JSObject* obj);
    844 #endif
    845 
    846 } /* namespace js */
    847 
    848 #endif /* js_Class_h */