| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- /* JSClass definition and its component types, plus related interfaces. */
- #ifndef js_Class_h
- #define js_Class_h
- #include "jstypes.h"
- #include "js/CallArgs.h"
- #include "js/Id.h"
- #include "js/TypeDecls.h"
- /*
- * A JSClass acts as a vtable for JS objects that allows JSAPI clients to
- * control various aspects of the behavior of an object like property lookup.
- * js::Class is an engine-private extension that allows more control over
- * object behavior and, e.g., allows custom slow layout.
- */
- struct JSAtomState;
- struct JSFreeOp;
- struct JSFunctionSpec;
- namespace js {
- struct Class;
- class FreeOp;
- class Shape;
- // This is equal to JSFunction::class_. Use it in places where you don't want
- // to #include jsfun.h.
- extern JS_FRIEND_DATA(const js::Class* const) FunctionClassPtr;
- } // namespace js
- namespace JS {
- class AutoIdVector;
- /**
- * The answer to a successful query as to whether an object is an Array per
- * ES6's internal |IsArray| operation (as exposed by |Array.isArray|).
- */
- enum class IsArrayAnswer
- {
- Array,
- NotArray,
- RevokedProxy
- };
- /**
- * ES6 7.2.2.
- *
- * Returns false on failure, otherwise returns true and sets |*isArray|
- * indicating whether the object passes ECMAScript's IsArray test. This is the
- * same test performed by |Array.isArray|.
- *
- * This is NOT the same as asking whether |obj| is an Array or a wrapper around
- * one. If |obj| is a proxy created by |Proxy.revocable()| and has been
- * revoked, or if |obj| is a proxy whose target (at any number of hops) is a
- * revoked proxy, this method throws a TypeError and returns false.
- */
- extern JS_PUBLIC_API(bool)
- IsArray(JSContext* cx, HandleObject obj, bool* isArray);
- /**
- * Identical to IsArray above, but the nature of the object (if successfully
- * determined) is communicated via |*answer|. In particular this method
- * returns true and sets |*answer = IsArrayAnswer::RevokedProxy| when called on
- * a revoked proxy.
- *
- * Most users will want the overload above, not this one.
- */
- extern JS_PUBLIC_API(bool)
- IsArray(JSContext* cx, HandleObject obj, IsArrayAnswer* answer);
- /**
- * Per ES6, the [[DefineOwnProperty]] internal method has three different
- * possible outcomes:
- *
- * - It can throw an exception (which we indicate by returning false).
- *
- * - It can return true, indicating unvarnished success.
- *
- * - It can return false, indicating "strict failure". The property could
- * not be defined. It's an error, but no exception was thrown.
- *
- * It's not just [[DefineOwnProperty]]: all the mutating internal methods have
- * the same three outcomes. (The other affected internal methods are [[Set]],
- * [[Delete]], [[SetPrototypeOf]], and [[PreventExtensions]].)
- *
- * If you think this design is awful, you're not alone. But as it's the
- * standard, we must represent these boolean "success" values somehow.
- * ObjectOpSuccess is the class for this. It's like a bool, but when it's false
- * it also stores an error code.
- *
- * Typical usage:
- *
- * ObjectOpResult result;
- * if (!DefineProperty(cx, obj, id, ..., result))
- * return false;
- * if (!result)
- * return result.reportError(cx, obj, id);
- *
- * Users don't have to call `result.report()`; another possible ending is:
- *
- * argv.rval().setBoolean(bool(result));
- * return true;
- */
- class ObjectOpResult
- {
- private:
- /**
- * code_ is either one of the special codes OkCode or Uninitialized, or
- * an error code. For now the error codes are private to the JS engine;
- * they're defined in js/src/js.msg.
- *
- * code_ is uintptr_t (rather than uint32_t) for the convenience of the
- * JITs, which would otherwise have to deal with either padding or stack
- * alignment on 64-bit platforms.
- */
- uintptr_t code_;
- public:
- enum SpecialCodes : uintptr_t {
- OkCode = 0,
- Uninitialized = uintptr_t(-1)
- };
- ObjectOpResult() : code_(Uninitialized) {}
- /* Return true if succeed() was called. */
- bool ok() const {
- MOZ_ASSERT(code_ != Uninitialized);
- return code_ == OkCode;
- }
- explicit operator bool() const { return ok(); }
- /* Set this ObjectOpResult to true and return true. */
- bool succeed() {
- code_ = OkCode;
- return true;
- }
- /*
- * Set this ObjectOpResult to false with an error code.
- *
- * Always returns true, as a convenience. Typical usage will be:
- *
- * if (funny condition)
- * return result.fail(JSMSG_CANT_DO_THE_THINGS);
- *
- * The true return value indicates that no exception is pending, and it
- * would be OK to ignore the failure and continue.
- */
- bool fail(uint32_t msg) {
- MOZ_ASSERT(msg != OkCode);
- code_ = msg;
- return true;
- }
- JS_PUBLIC_API(bool) failCantRedefineProp();
- JS_PUBLIC_API(bool) failReadOnly();
- JS_PUBLIC_API(bool) failGetterOnly();
- JS_PUBLIC_API(bool) failCantDelete();
- JS_PUBLIC_API(bool) failCantSetInterposed();
- JS_PUBLIC_API(bool) failCantDefineWindowElement();
- JS_PUBLIC_API(bool) failCantDeleteWindowElement();
- JS_PUBLIC_API(bool) failCantDeleteWindowNamedProperty();
- JS_PUBLIC_API(bool) failCantPreventExtensions();
- JS_PUBLIC_API(bool) failCantSetProto();
- JS_PUBLIC_API(bool) failNoNamedSetter();
- JS_PUBLIC_API(bool) failNoIndexedSetter();
- uint32_t failureCode() const {
- MOZ_ASSERT(!ok());
- return uint32_t(code_);
- }
- /*
- * Report an error or warning if necessary; return true to proceed and
- * false if an error was reported. Call this when failure should cause
- * a warning if extraWarnings are enabled.
- *
- * The precise rules are like this:
- *
- * - If ok(), then we succeeded. Do nothing and return true.
- * - Otherwise, if |strict| is true, or if cx has both extraWarnings and
- * werrorOption enabled, throw a TypeError and return false.
- * - Otherwise, if cx has extraWarnings enabled, emit a warning and
- * return true.
- * - Otherwise, do nothing and return true.
- */
- bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, HandleId id, bool strict) {
- if (ok())
- return true;
- return reportStrictErrorOrWarning(cx, obj, id, strict);
- }
- /*
- * The same as checkStrictErrorOrWarning(cx, id, strict), except the
- * operation is not associated with a particular property id. This is
- * used for [[PreventExtensions]] and [[SetPrototypeOf]]. failureCode()
- * must not be an error that has "{0}" in the error message.
- */
- bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, bool strict) {
- return ok() || reportStrictErrorOrWarning(cx, obj, strict);
- }
- /* Throw a TypeError. Call this only if !ok(). */
- bool reportError(JSContext* cx, HandleObject obj, HandleId id) {
- return reportStrictErrorOrWarning(cx, obj, id, true);
- }
- /*
- * The same as reportError(cx, obj, id), except the operation is not
- * associated with a particular property id.
- */
- bool reportError(JSContext* cx, HandleObject obj) {
- return reportStrictErrorOrWarning(cx, obj, true);
- }
- /* Helper function for checkStrictErrorOrWarning's slow path. */
- JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, HandleId id, bool strict);
- JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, bool strict);
- /*
- * Convenience method. Return true if ok() or if strict is false; otherwise
- * throw a TypeError and return false.
- */
- bool checkStrict(JSContext* cx, HandleObject obj, HandleId id) {
- return checkStrictErrorOrWarning(cx, obj, id, true);
- }
- /*
- * Convenience method. The same as checkStrict(cx, id), except the
- * operation is not associated with a particular property id.
- */
- bool checkStrict(JSContext* cx, HandleObject obj) {
- return checkStrictErrorOrWarning(cx, obj, true);
- }
- };
- } // namespace JS
- // JSClass operation signatures.
- /**
- * Get a property named by id in obj. Note the jsid id type -- id may
- * be a string (Unicode property identifier) or an int (element index). The
- * *vp out parameter, on success, is the new property value after the action.
- */
- typedef bool
- (* JSGetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
- JS::MutableHandleValue vp);
- /** Add a property named by id to obj. */
- typedef bool
- (* JSAddPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v);
- /**
- * Set a property named by id in obj, treating the assignment as strict
- * mode code if strict is true. Note the jsid id type -- id may be a string
- * (Unicode property identifier) or an int (element index). The *vp out
- * parameter, on success, is the new property value after the
- * set.
- */
- typedef bool
- (* JSSetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
- JS::MutableHandleValue vp, JS::ObjectOpResult& result);
- /**
- * Delete a property named by id in obj.
- *
- * If an error occurred, return false as per normal JSAPI error practice.
- *
- * If no error occurred, but the deletion attempt wasn't allowed (perhaps
- * because the property was non-configurable), call result.fail() and
- * return true. This will cause |delete obj[id]| to evaluate to false in
- * non-strict mode code, and to throw a TypeError in strict mode code.
- *
- * If no error occurred and the deletion wasn't disallowed (this is *not* the
- * same as saying that a deletion actually occurred -- deleting a non-existent
- * property, or an inherited property, is allowed -- it's just pointless),
- * call result.succeed() and return true.
- */
- typedef bool
- (* JSDeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
- JS::ObjectOpResult& result);
- /**
- * The type of ObjectOps::enumerate. This callback overrides a portion of
- * SpiderMonkey's default [[Enumerate]] internal method. When an ordinary object
- * is enumerated, that object and each object on its prototype chain is tested
- * for an enumerate op, and those ops are called in order. The properties each
- * op adds to the 'properties' vector are added to the set of values the for-in
- * loop will iterate over. All of this is nonstandard.
- *
- * An object is "enumerated" when it's the target of a for-in loop or
- * JS_Enumerate(). The callback's job is to populate 'properties' with the
- * object's property keys. If `enumerableOnly` is true, the callback should only
- * add enumerable properties.
- */
- typedef bool
- (* JSNewEnumerateOp)(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
- bool enumerableOnly);
- /**
- * The old-style JSClass.enumerate op should define all lazy properties not
- * yet reflected in obj.
- */
- typedef bool
- (* JSEnumerateOp)(JSContext* cx, JS::HandleObject obj);
- /**
- * The type of ObjectOps::funToString. This callback allows an object to
- * provide a custom string to use when Function.prototype.toString is invoked on
- * that object. A null return value means OOM.
- */
- typedef JSString*
- (* JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, unsigned indent);
- /**
- * Resolve a lazy property named by id in obj by defining it directly in obj.
- * Lazy properties are those reflected from some peer native property space
- * (e.g., the DOM attributes for a given node reflected as obj) on demand.
- *
- * JS looks for a property in an object, and if not found, tries to resolve
- * the given id. *resolvedp should be set to true iff the property was defined
- * on |obj|.
- */
- typedef bool
- (* JSResolveOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
- bool* resolvedp);
- /**
- * A class with a resolve hook can optionally have a mayResolve hook. This hook
- * must have no side effects and must return true for a given id if the resolve
- * hook may resolve this id. This is useful when we're doing a "pure" lookup: if
- * mayResolve returns false, we know we don't have to call the effectful resolve
- * hook.
- *
- * maybeObj, if non-null, is the object on which we're doing the lookup. This
- * can be nullptr: during JIT compilation we sometimes know the Class but not
- * the object.
- */
- typedef bool
- (* JSMayResolveOp)(const JSAtomState& names, jsid id, JSObject* maybeObj);
- /**
- * Finalize obj, which the garbage collector has determined to be unreachable
- * from other live objects or from GC roots. Obviously, finalizers must never
- * store a reference to obj.
- */
- typedef void
- (* JSFinalizeOp)(JSFreeOp* fop, JSObject* obj);
- /** Finalizes external strings created by JS_NewExternalString. */
- struct JSStringFinalizer {
- void (*finalize)(JS::Zone* zone, const JSStringFinalizer* fin, char16_t* chars);
- };
- /**
- * Check whether v is an instance of obj. Return false on error or exception,
- * true on success with true in *bp if v is an instance of obj, false in
- * *bp otherwise.
- */
- typedef bool
- (* JSHasInstanceOp)(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp,
- bool* bp);
- /**
- * Function type for trace operation of the class called to enumerate all
- * traceable things reachable from obj's private data structure. For each such
- * thing, a trace implementation must call JS::TraceEdge on the thing's
- * location.
- *
- * JSTraceOp implementation can assume that no other threads mutates object
- * state. It must not change state of the object or corresponding native
- * structures. The only exception for this rule is the case when the embedding
- * needs a tight integration with GC. In that case the embedding can check if
- * the traversal is a part of the marking phase through calling
- * JS_IsGCMarkingTracer and apply a special code like emptying caches or
- * marking its native structures.
- */
- typedef void
- (* JSTraceOp)(JSTracer* trc, JSObject* obj);
- typedef JSObject*
- (* JSWeakmapKeyDelegateOp)(JSObject* obj);
- typedef void
- (* JSObjectMovedOp)(JSObject* obj, const JSObject* old);
- /* js::Class operation signatures. */
- namespace js {
- typedef bool
- (* LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
- JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
- typedef bool
- (* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
- JS::Handle<JS::PropertyDescriptor> desc,
- JS::ObjectOpResult& result);
- typedef bool
- (* HasPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
- typedef bool
- (* GetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id,
- JS::MutableHandleValue vp);
- typedef bool
- (* SetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v,
- JS::HandleValue receiver, JS::ObjectOpResult& result);
- typedef bool
- (* GetOwnPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
- JS::MutableHandle<JS::PropertyDescriptor> desc);
- typedef bool
- (* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
- JS::ObjectOpResult& result);
- typedef bool
- (* WatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
- typedef bool
- (* UnwatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id);
- class JS_FRIEND_API(ElementAdder)
- {
- public:
- enum GetBehavior {
- // Check if the element exists before performing the Get and preserve
- // holes.
- CheckHasElemPreserveHoles,
- // Perform a Get operation, like obj[index] in JS.
- GetElement
- };
- private:
- // Only one of these is used.
- JS::RootedObject resObj_;
- JS::Value* vp_;
- uint32_t index_;
- #ifdef DEBUG
- uint32_t length_;
- #endif
- GetBehavior getBehavior_;
- public:
- ElementAdder(JSContext* cx, JSObject* obj, uint32_t length, GetBehavior behavior)
- : resObj_(cx, obj), vp_(nullptr), index_(0),
- #ifdef DEBUG
- length_(length),
- #endif
- getBehavior_(behavior)
- {}
- ElementAdder(JSContext* cx, JS::Value* vp, uint32_t length, GetBehavior behavior)
- : resObj_(cx), vp_(vp), index_(0),
- #ifdef DEBUG
- length_(length),
- #endif
- getBehavior_(behavior)
- {}
- GetBehavior getBehavior() const { return getBehavior_; }
- bool append(JSContext* cx, JS::HandleValue v);
- void appendHole();
- };
- typedef bool
- (* GetElementsOp)(JSContext* cx, JS::HandleObject obj, uint32_t begin, uint32_t end,
- ElementAdder* adder);
- typedef void
- (* FinalizeOp)(FreeOp* fop, JSObject* obj);
- // The special treatment of |finalize| and |trace| is necessary because if we
- // assign either of those hooks to a local variable and then call it -- as is
- // done with the other hooks -- the GC hazard analysis gets confused.
- #define JS_CLASS_MEMBERS(ClassOpsType, FreeOpType) \
- const char* name; \
- uint32_t flags; \
- const ClassOpsType* cOps; \
- \
- JSAddPropertyOp getAddProperty() const { return cOps ? cOps->addProperty : nullptr; } \
- JSDeletePropertyOp getDelProperty() const { return cOps ? cOps->delProperty : nullptr; } \
- JSGetterOp getGetProperty() const { return cOps ? cOps->getProperty : nullptr; } \
- JSSetterOp getSetProperty() const { return cOps ? cOps->setProperty : nullptr; } \
- JSEnumerateOp getEnumerate() const { return cOps ? cOps->enumerate : nullptr; } \
- JSResolveOp getResolve() const { return cOps ? cOps->resolve : nullptr; } \
- JSMayResolveOp getMayResolve() const { return cOps ? cOps->mayResolve : nullptr; } \
- JSNative getCall() const { return cOps ? cOps->call : nullptr; } \
- JSHasInstanceOp getHasInstance() const { return cOps ? cOps->hasInstance : nullptr; } \
- JSNative getConstruct() const { return cOps ? cOps->construct : nullptr; } \
- \
- bool hasFinalize() const { return cOps && cOps->finalize; } \
- bool hasTrace() const { return cOps && cOps->trace; } \
- \
- bool isTrace(JSTraceOp trace) const { return cOps && cOps->trace == trace; } \
- \
- void doFinalize(FreeOpType* fop, JSObject* obj) const { \
- MOZ_ASSERT(cOps && cOps->finalize); \
- cOps->finalize(fop, obj); \
- } \
- void doTrace(JSTracer* trc, JSObject* obj) const { \
- MOZ_ASSERT(cOps && cOps->trace); \
- cOps->trace(trc, obj); \
- }
- struct ClassOps
- {
- /* Function pointer members (may be null). */
- JSAddPropertyOp addProperty;
- JSDeletePropertyOp delProperty;
- JSGetterOp getProperty;
- JSSetterOp setProperty;
- JSEnumerateOp enumerate;
- JSResolveOp resolve;
- JSMayResolveOp mayResolve;
- FinalizeOp finalize;
- JSNative call;
- JSHasInstanceOp hasInstance;
- JSNative construct;
- JSTraceOp trace;
- };
- /** Callback for the creation of constructor and prototype objects. */
- typedef JSObject* (*ClassObjectCreationOp)(JSContext* cx, JSProtoKey key);
- /** Callback for custom post-processing after class initialization via ClassSpec. */
- typedef bool (*FinishClassInitOp)(JSContext* cx, JS::HandleObject ctor,
- JS::HandleObject proto);
- const size_t JSCLASS_CACHED_PROTO_WIDTH = 6;
- struct ClassSpec
- {
- // All properties except flags should be accessed through accessor.
- ClassObjectCreationOp createConstructor_;
- ClassObjectCreationOp createPrototype_;
- const JSFunctionSpec* constructorFunctions_;
- const JSPropertySpec* constructorProperties_;
- const JSFunctionSpec* prototypeFunctions_;
- const JSPropertySpec* prototypeProperties_;
- FinishClassInitOp finishInit_;
- uintptr_t flags;
- static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH;
- static const uintptr_t ProtoKeyMask = (1 << ProtoKeyWidth) - 1;
- static const uintptr_t DontDefineConstructor = 1 << ProtoKeyWidth;
- static const uintptr_t IsDelegated = 1 << (ProtoKeyWidth + 1);
- bool defined() const { return !!createConstructor_; }
- bool delegated() const {
- return (flags & IsDelegated);
- }
- // The ProtoKey this class inherits from.
- JSProtoKey inheritanceProtoKey() const {
- MOZ_ASSERT(defined());
- static_assert(JSProto_Null == 0, "zeroed key must be null");
- // Default: Inherit from Object.
- if (!(flags & ProtoKeyMask))
- return JSProto_Object;
- return JSProtoKey(flags & ProtoKeyMask);
- }
- bool shouldDefineConstructor() const {
- MOZ_ASSERT(defined());
- return !(flags & DontDefineConstructor);
- }
- const ClassSpec* delegatedClassSpec() const {
- MOZ_ASSERT(delegated());
- return reinterpret_cast<ClassSpec*>(createConstructor_);
- }
- ClassObjectCreationOp createConstructorHook() const {
- if (delegated())
- return delegatedClassSpec()->createConstructorHook();
- return createConstructor_;
- }
- ClassObjectCreationOp createPrototypeHook() const {
- if (delegated())
- return delegatedClassSpec()->createPrototypeHook();
- return createPrototype_;
- }
- const JSFunctionSpec* constructorFunctions() const {
- if (delegated())
- return delegatedClassSpec()->constructorFunctions();
- return constructorFunctions_;
- }
- const JSPropertySpec* constructorProperties() const {
- if (delegated())
- return delegatedClassSpec()->constructorProperties();
- return constructorProperties_;
- }
- const JSFunctionSpec* prototypeFunctions() const {
- if (delegated())
- return delegatedClassSpec()->prototypeFunctions();
- return prototypeFunctions_;
- }
- const JSPropertySpec* prototypeProperties() const {
- if (delegated())
- return delegatedClassSpec()->prototypeProperties();
- return prototypeProperties_;
- }
- FinishClassInitOp finishInitHook() const {
- if (delegated())
- return delegatedClassSpec()->finishInitHook();
- return finishInit_;
- }
- };
- struct ClassExtension
- {
- /**
- * If an object is used as a key in a weakmap, it may be desirable for the
- * garbage collector to keep that object around longer than it otherwise
- * would. A common case is when the key is a wrapper around an object in
- * another compartment, and we want to avoid collecting the wrapper (and
- * removing the weakmap entry) as long as the wrapped object is alive. In
- * that case, the wrapped object is returned by the wrapper's
- * weakmapKeyDelegateOp hook. As long as the wrapper is used as a weakmap
- * key, it will not be collected (and remain in the weakmap) until the
- * wrapped object is collected.
- */
- JSWeakmapKeyDelegateOp weakmapKeyDelegateOp;
- /**
- * Optional hook called when an object is moved by a compacting GC.
- *
- * There may exist weak pointers to an object that are not traced through
- * when the normal trace APIs are used, for example objects in the wrapper
- * cache. This hook allows these pointers to be updated.
- *
- * Note that this hook can be called before JS_NewObject() returns if a GC
- * is triggered during construction of the object. This can happen for
- * global objects for example.
- */
- JSObjectMovedOp objectMovedOp;
- };
- inline ClassObjectCreationOp DELEGATED_CLASSSPEC(const ClassSpec* spec) {
- return reinterpret_cast<ClassObjectCreationOp>(const_cast<ClassSpec*>(spec));
- }
- #define JS_NULL_CLASS_SPEC nullptr
- #define JS_NULL_CLASS_EXT nullptr
- struct ObjectOps
- {
- LookupPropertyOp lookupProperty;
- DefinePropertyOp defineProperty;
- HasPropertyOp hasProperty;
- GetPropertyOp getProperty;
- SetPropertyOp setProperty;
- GetOwnPropertyOp getOwnPropertyDescriptor;
- DeletePropertyOp deleteProperty;
- WatchOp watch;
- UnwatchOp unwatch;
- GetElementsOp getElements;
- JSNewEnumerateOp enumerate;
- JSFunToStringOp funToString;
- };
- #define JS_NULL_OBJECT_OPS nullptr
- } // namespace js
- // Classes, objects, and properties.
- typedef void (*JSClassInternal)();
- struct JSClassOps
- {
- /* Function pointer members (may be null). */
- JSAddPropertyOp addProperty;
- JSDeletePropertyOp delProperty;
- JSGetterOp getProperty;
- JSSetterOp setProperty;
- JSEnumerateOp enumerate;
- JSResolveOp resolve;
- JSMayResolveOp mayResolve;
- JSFinalizeOp finalize;
- JSNative call;
- JSHasInstanceOp hasInstance;
- JSNative construct;
- JSTraceOp trace;
- };
- #define JS_NULL_CLASS_OPS nullptr
- struct JSClass {
- JS_CLASS_MEMBERS(JSClassOps, JSFreeOp);
- void* reserved[3];
- };
- #define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot
- #define JSCLASS_DELAY_METADATA_BUILDER (1<<1) // class's initialization code
- // will call
- // SetNewObjectMetadata itself
- #define JSCLASS_IS_WRAPPED_NATIVE (1<<2) // class is an XPCWrappedNative.
- // WeakMaps use this to override
- // the wrapper disposal
- // mechanism.
- #define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) // private is (nsISupports*)
- #define JSCLASS_IS_DOMJSCLASS (1<<4) // objects are DOM
- #define JSCLASS_HAS_XRAYED_CONSTRUCTOR (1<<5) // if wrapped by an xray
- // wrapper, the builtin
- // class's constructor won't
- // be unwrapped and invoked.
- // Instead, the constructor is
- // resolved in the caller's
- // compartment and invoked
- // with a wrapped newTarget.
- // The constructor has to
- // detect and handle this
- // situation.
- // See PromiseConstructor for
- // details.
- #define JSCLASS_EMULATES_UNDEFINED (1<<6) // objects of this class act
- // like the value undefined,
- // in some contexts
- #define JSCLASS_USERBIT1 (1<<7) // Reserved for embeddings.
- // To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
- // JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where
- // n is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1.
- #define JSCLASS_RESERVED_SLOTS_SHIFT 8 // room for 8 flags below */
- #define JSCLASS_RESERVED_SLOTS_WIDTH 8 // and 16 above this field */
- #define JSCLASS_RESERVED_SLOTS_MASK JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH)
- #define JSCLASS_HAS_RESERVED_SLOTS(n) (((n) & JSCLASS_RESERVED_SLOTS_MASK) \
- << JSCLASS_RESERVED_SLOTS_SHIFT)
- #define JSCLASS_RESERVED_SLOTS(clasp) (((clasp)->flags \
- >> JSCLASS_RESERVED_SLOTS_SHIFT) \
- & JSCLASS_RESERVED_SLOTS_MASK)
- #define JSCLASS_HIGH_FLAGS_SHIFT (JSCLASS_RESERVED_SLOTS_SHIFT + \
- JSCLASS_RESERVED_SLOTS_WIDTH)
- #define JSCLASS_IS_ANONYMOUS (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0))
- #define JSCLASS_IS_GLOBAL (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1))
- #define JSCLASS_INTERNAL_FLAG2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2))
- #define JSCLASS_INTERNAL_FLAG3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3))
- #define JSCLASS_IS_PROXY (1<<(JSCLASS_HIGH_FLAGS_SHIFT+4))
- #define JSCLASS_SKIP_NURSERY_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+5))
- // Reserved for embeddings.
- #define JSCLASS_USERBIT2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6))
- #define JSCLASS_USERBIT3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7))
- #define JSCLASS_BACKGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+8))
- #define JSCLASS_FOREGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+9))
- // Bits 26 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see
- // below.
- // ECMA-262 requires that most constructors used internally create objects
- // with "the original Foo.prototype value" as their [[Prototype]] (__proto__)
- // member initial value. The "original ... value" verbiage is there because
- // in ECMA-262, global properties naming class objects are read/write and
- // deleteable, for the most part.
- //
- // Implementing this efficiently requires that global objects have classes
- // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
- // previously allowed, but is now an ES5 violation and thus unsupported.
- //
- // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
- // the beginning of every global object's slots for use by the
- // application.
- #define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
- #define JSCLASS_GLOBAL_SLOT_COUNT \
- (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 39)
- #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
- (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
- #define JSCLASS_GLOBAL_FLAGS \
- JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
- #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \
- (((clasp)->flags & JSCLASS_IS_GLOBAL) \
- && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
- // Fast access to the original value of each standard class's prototype.
- #define JSCLASS_CACHED_PROTO_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT + 10)
- #define JSCLASS_CACHED_PROTO_MASK JS_BITMASK(js::JSCLASS_CACHED_PROTO_WIDTH)
- #define JSCLASS_HAS_CACHED_PROTO(key) (uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT)
- #define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey) \
- (((clasp)->flags \
- >> JSCLASS_CACHED_PROTO_SHIFT) \
- & JSCLASS_CACHED_PROTO_MASK))
- // Initializer for unused members of statically initialized JSClass structs.
- #define JSCLASS_NO_INTERNAL_MEMBERS {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
- #define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS
- namespace js {
- struct Class
- {
- JS_CLASS_MEMBERS(js::ClassOps, FreeOp);
- const ClassSpec* spec;
- const ClassExtension* ext;
- const ObjectOps* oOps;
- /*
- * Objects of this class aren't native objects. They don't have Shapes that
- * describe their properties and layout. Classes using this flag must
- * provide their own property behavior, either by being proxy classes (do
- * this) or by overriding all the ObjectOps except getElements, watch and
- * unwatch (don't do this).
- */
- static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
- bool isNative() const {
- return !(flags & NON_NATIVE);
- }
- bool hasPrivate() const {
- return !!(flags & JSCLASS_HAS_PRIVATE);
- }
- bool emulatesUndefined() const {
- return flags & JSCLASS_EMULATES_UNDEFINED;
- }
- bool isJSFunction() const {
- return this == js::FunctionClassPtr;
- }
- bool nonProxyCallable() const {
- MOZ_ASSERT(!isProxy());
- return isJSFunction() || getCall();
- }
- bool isProxy() const {
- return flags & JSCLASS_IS_PROXY;
- }
- bool isDOMClass() const {
- return flags & JSCLASS_IS_DOMJSCLASS;
- }
- bool shouldDelayMetadataBuilder() const {
- return flags & JSCLASS_DELAY_METADATA_BUILDER;
- }
- bool isWrappedNative() const {
- return flags & JSCLASS_IS_WRAPPED_NATIVE;
- }
- static size_t offsetOfFlags() { return offsetof(Class, flags); }
- bool specDefined() const { return spec ? spec->defined() : false; }
- JSProtoKey specInheritanceProtoKey()
- const { return spec ? spec->inheritanceProtoKey() : JSProto_Null; }
- bool specShouldDefineConstructor()
- const { return spec ? spec->shouldDefineConstructor() : true; }
- ClassObjectCreationOp specCreateConstructorHook()
- const { return spec ? spec->createConstructorHook() : nullptr; }
- ClassObjectCreationOp specCreatePrototypeHook()
- const { return spec ? spec->createPrototypeHook() : nullptr; }
- const JSFunctionSpec* specConstructorFunctions()
- const { return spec ? spec->constructorFunctions() : nullptr; }
- const JSPropertySpec* specConstructorProperties()
- const { return spec ? spec->constructorProperties() : nullptr; }
- const JSFunctionSpec* specPrototypeFunctions()
- const { return spec ? spec->prototypeFunctions() : nullptr; }
- const JSPropertySpec* specPrototypeProperties()
- const { return spec ? spec->prototypeProperties() : nullptr; }
- FinishClassInitOp specFinishInitHook()
- const { return spec ? spec->finishInitHook() : nullptr; }
- JSWeakmapKeyDelegateOp extWeakmapKeyDelegateOp()
- const { return ext ? ext->weakmapKeyDelegateOp : nullptr; }
- JSObjectMovedOp extObjectMovedOp()
- const { return ext ? ext->objectMovedOp : nullptr; }
- LookupPropertyOp getOpsLookupProperty() const { return oOps ? oOps->lookupProperty : nullptr; }
- DefinePropertyOp getOpsDefineProperty() const { return oOps ? oOps->defineProperty : nullptr; }
- HasPropertyOp getOpsHasProperty() const { return oOps ? oOps->hasProperty : nullptr; }
- GetPropertyOp getOpsGetProperty() const { return oOps ? oOps->getProperty : nullptr; }
- SetPropertyOp getOpsSetProperty() const { return oOps ? oOps->setProperty : nullptr; }
- GetOwnPropertyOp getOpsGetOwnPropertyDescriptor()
- const { return oOps ? oOps->getOwnPropertyDescriptor
- : nullptr; }
- DeletePropertyOp getOpsDeleteProperty() const { return oOps ? oOps->deleteProperty : nullptr; }
- WatchOp getOpsWatch() const { return oOps ? oOps->watch : nullptr; }
- UnwatchOp getOpsUnwatch() const { return oOps ? oOps->unwatch : nullptr; }
- GetElementsOp getOpsGetElements() const { return oOps ? oOps->getElements : nullptr; }
- JSNewEnumerateOp getOpsEnumerate() const { return oOps ? oOps->enumerate : nullptr; }
- JSFunToStringOp getOpsFunToString() const { return oOps ? oOps->funToString : nullptr; }
- };
- static_assert(offsetof(JSClassOps, addProperty) == offsetof(ClassOps, addProperty),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClassOps, delProperty) == offsetof(ClassOps, delProperty),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClassOps, getProperty) == offsetof(ClassOps, getProperty),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClassOps, setProperty) == offsetof(ClassOps, setProperty),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClassOps, enumerate) == offsetof(ClassOps, enumerate),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClassOps, resolve) == offsetof(ClassOps, resolve),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClassOps, mayResolve) == offsetof(ClassOps, mayResolve),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClassOps, finalize) == offsetof(ClassOps, finalize),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClassOps, call) == offsetof(ClassOps, call),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClassOps, construct) == offsetof(ClassOps, construct),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClassOps, hasInstance) == offsetof(ClassOps, hasInstance),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClassOps, trace) == offsetof(ClassOps, trace),
- "ClassOps and JSClassOps must be consistent");
- static_assert(sizeof(JSClassOps) == sizeof(ClassOps),
- "ClassOps and JSClassOps must be consistent");
- static_assert(offsetof(JSClass, name) == offsetof(Class, name),
- "Class and JSClass must be consistent");
- static_assert(offsetof(JSClass, flags) == offsetof(Class, flags),
- "Class and JSClass must be consistent");
- static_assert(offsetof(JSClass, cOps) == offsetof(Class, cOps),
- "Class and JSClass must be consistent");
- static_assert(sizeof(JSClass) == sizeof(Class),
- "Class and JSClass must be consistent");
- static MOZ_ALWAYS_INLINE const JSClass*
- Jsvalify(const Class* c)
- {
- return (const JSClass*)c;
- }
- static MOZ_ALWAYS_INLINE const Class*
- Valueify(const JSClass* c)
- {
- return (const Class*)c;
- }
- /**
- * Enumeration describing possible values of the [[Class]] internal property
- * value of objects.
- */
- enum class ESClass {
- Object,
- Array,
- Number,
- String,
- Boolean,
- RegExp,
- ArrayBuffer,
- SharedArrayBuffer,
- Date,
- Set,
- Map,
- Promise,
- MapIterator,
- SetIterator,
- Arguments,
- Error,
- /** None of the above. */
- Other
- };
- /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */
- bool
- Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp);
- #ifdef DEBUG
- JS_FRIEND_API(bool)
- HasObjectMovedOp(JSObject* obj);
- #endif
- } /* namespace js */
- #endif /* js_Class_h */
|