Class.h 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sts=4 et sw=4 tw=99:
  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. /* JSClass definition and its component types, plus related interfaces. */
  7. #ifndef js_Class_h
  8. #define js_Class_h
  9. #include "jstypes.h"
  10. #include "js/CallArgs.h"
  11. #include "js/Id.h"
  12. #include "js/TypeDecls.h"
  13. /*
  14. * A JSClass acts as a vtable for JS objects that allows JSAPI clients to
  15. * control various aspects of the behavior of an object like property lookup.
  16. * js::Class is an engine-private extension that allows more control over
  17. * object behavior and, e.g., allows custom slow layout.
  18. */
  19. struct JSAtomState;
  20. struct JSFreeOp;
  21. struct JSFunctionSpec;
  22. namespace js {
  23. struct Class;
  24. class FreeOp;
  25. class Shape;
  26. // This is equal to JSFunction::class_. Use it in places where you don't want
  27. // to #include jsfun.h.
  28. extern JS_FRIEND_DATA(const js::Class* const) FunctionClassPtr;
  29. } // namespace js
  30. namespace JS {
  31. class AutoIdVector;
  32. /**
  33. * The answer to a successful query as to whether an object is an Array per
  34. * ES6's internal |IsArray| operation (as exposed by |Array.isArray|).
  35. */
  36. enum class IsArrayAnswer
  37. {
  38. Array,
  39. NotArray,
  40. RevokedProxy
  41. };
  42. /**
  43. * ES6 7.2.2.
  44. *
  45. * Returns false on failure, otherwise returns true and sets |*isArray|
  46. * indicating whether the object passes ECMAScript's IsArray test. This is the
  47. * same test performed by |Array.isArray|.
  48. *
  49. * This is NOT the same as asking whether |obj| is an Array or a wrapper around
  50. * one. If |obj| is a proxy created by |Proxy.revocable()| and has been
  51. * revoked, or if |obj| is a proxy whose target (at any number of hops) is a
  52. * revoked proxy, this method throws a TypeError and returns false.
  53. */
  54. extern JS_PUBLIC_API(bool)
  55. IsArray(JSContext* cx, HandleObject obj, bool* isArray);
  56. /**
  57. * Identical to IsArray above, but the nature of the object (if successfully
  58. * determined) is communicated via |*answer|. In particular this method
  59. * returns true and sets |*answer = IsArrayAnswer::RevokedProxy| when called on
  60. * a revoked proxy.
  61. *
  62. * Most users will want the overload above, not this one.
  63. */
  64. extern JS_PUBLIC_API(bool)
  65. IsArray(JSContext* cx, HandleObject obj, IsArrayAnswer* answer);
  66. /**
  67. * Per ES6, the [[DefineOwnProperty]] internal method has three different
  68. * possible outcomes:
  69. *
  70. * - It can throw an exception (which we indicate by returning false).
  71. *
  72. * - It can return true, indicating unvarnished success.
  73. *
  74. * - It can return false, indicating "strict failure". The property could
  75. * not be defined. It's an error, but no exception was thrown.
  76. *
  77. * It's not just [[DefineOwnProperty]]: all the mutating internal methods have
  78. * the same three outcomes. (The other affected internal methods are [[Set]],
  79. * [[Delete]], [[SetPrototypeOf]], and [[PreventExtensions]].)
  80. *
  81. * If you think this design is awful, you're not alone. But as it's the
  82. * standard, we must represent these boolean "success" values somehow.
  83. * ObjectOpSuccess is the class for this. It's like a bool, but when it's false
  84. * it also stores an error code.
  85. *
  86. * Typical usage:
  87. *
  88. * ObjectOpResult result;
  89. * if (!DefineProperty(cx, obj, id, ..., result))
  90. * return false;
  91. * if (!result)
  92. * return result.reportError(cx, obj, id);
  93. *
  94. * Users don't have to call `result.report()`; another possible ending is:
  95. *
  96. * argv.rval().setBoolean(bool(result));
  97. * return true;
  98. */
  99. class ObjectOpResult
  100. {
  101. private:
  102. /**
  103. * code_ is either one of the special codes OkCode or Uninitialized, or
  104. * an error code. For now the error codes are private to the JS engine;
  105. * they're defined in js/src/js.msg.
  106. *
  107. * code_ is uintptr_t (rather than uint32_t) for the convenience of the
  108. * JITs, which would otherwise have to deal with either padding or stack
  109. * alignment on 64-bit platforms.
  110. */
  111. uintptr_t code_;
  112. public:
  113. enum SpecialCodes : uintptr_t {
  114. OkCode = 0,
  115. Uninitialized = uintptr_t(-1)
  116. };
  117. ObjectOpResult() : code_(Uninitialized) {}
  118. /* Return true if succeed() was called. */
  119. bool ok() const {
  120. MOZ_ASSERT(code_ != Uninitialized);
  121. return code_ == OkCode;
  122. }
  123. explicit operator bool() const { return ok(); }
  124. /* Set this ObjectOpResult to true and return true. */
  125. bool succeed() {
  126. code_ = OkCode;
  127. return true;
  128. }
  129. /*
  130. * Set this ObjectOpResult to false with an error code.
  131. *
  132. * Always returns true, as a convenience. Typical usage will be:
  133. *
  134. * if (funny condition)
  135. * return result.fail(JSMSG_CANT_DO_THE_THINGS);
  136. *
  137. * The true return value indicates that no exception is pending, and it
  138. * would be OK to ignore the failure and continue.
  139. */
  140. bool fail(uint32_t msg) {
  141. MOZ_ASSERT(msg != OkCode);
  142. code_ = msg;
  143. return true;
  144. }
  145. JS_PUBLIC_API(bool) failCantRedefineProp();
  146. JS_PUBLIC_API(bool) failReadOnly();
  147. JS_PUBLIC_API(bool) failGetterOnly();
  148. JS_PUBLIC_API(bool) failCantDelete();
  149. JS_PUBLIC_API(bool) failCantSetInterposed();
  150. JS_PUBLIC_API(bool) failCantDefineWindowElement();
  151. JS_PUBLIC_API(bool) failCantDeleteWindowElement();
  152. JS_PUBLIC_API(bool) failCantDeleteWindowNamedProperty();
  153. JS_PUBLIC_API(bool) failCantPreventExtensions();
  154. JS_PUBLIC_API(bool) failCantSetProto();
  155. JS_PUBLIC_API(bool) failNoNamedSetter();
  156. JS_PUBLIC_API(bool) failNoIndexedSetter();
  157. uint32_t failureCode() const {
  158. MOZ_ASSERT(!ok());
  159. return uint32_t(code_);
  160. }
  161. /*
  162. * Report an error or warning if necessary; return true to proceed and
  163. * false if an error was reported. Call this when failure should cause
  164. * a warning if extraWarnings are enabled.
  165. *
  166. * The precise rules are like this:
  167. *
  168. * - If ok(), then we succeeded. Do nothing and return true.
  169. * - Otherwise, if |strict| is true, or if cx has both extraWarnings and
  170. * werrorOption enabled, throw a TypeError and return false.
  171. * - Otherwise, if cx has extraWarnings enabled, emit a warning and
  172. * return true.
  173. * - Otherwise, do nothing and return true.
  174. */
  175. bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, HandleId id, bool strict) {
  176. if (ok())
  177. return true;
  178. return reportStrictErrorOrWarning(cx, obj, id, strict);
  179. }
  180. /*
  181. * The same as checkStrictErrorOrWarning(cx, id, strict), except the
  182. * operation is not associated with a particular property id. This is
  183. * used for [[PreventExtensions]] and [[SetPrototypeOf]]. failureCode()
  184. * must not be an error that has "{0}" in the error message.
  185. */
  186. bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, bool strict) {
  187. return ok() || reportStrictErrorOrWarning(cx, obj, strict);
  188. }
  189. /* Throw a TypeError. Call this only if !ok(). */
  190. bool reportError(JSContext* cx, HandleObject obj, HandleId id) {
  191. return reportStrictErrorOrWarning(cx, obj, id, true);
  192. }
  193. /*
  194. * The same as reportError(cx, obj, id), except the operation is not
  195. * associated with a particular property id.
  196. */
  197. bool reportError(JSContext* cx, HandleObject obj) {
  198. return reportStrictErrorOrWarning(cx, obj, true);
  199. }
  200. /* Helper function for checkStrictErrorOrWarning's slow path. */
  201. JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, HandleId id, bool strict);
  202. JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, bool strict);
  203. /*
  204. * Convenience method. Return true if ok() or if strict is false; otherwise
  205. * throw a TypeError and return false.
  206. */
  207. bool checkStrict(JSContext* cx, HandleObject obj, HandleId id) {
  208. return checkStrictErrorOrWarning(cx, obj, id, true);
  209. }
  210. /*
  211. * Convenience method. The same as checkStrict(cx, id), except the
  212. * operation is not associated with a particular property id.
  213. */
  214. bool checkStrict(JSContext* cx, HandleObject obj) {
  215. return checkStrictErrorOrWarning(cx, obj, true);
  216. }
  217. };
  218. } // namespace JS
  219. // JSClass operation signatures.
  220. /**
  221. * Get a property named by id in obj. Note the jsid id type -- id may
  222. * be a string (Unicode property identifier) or an int (element index). The
  223. * *vp out parameter, on success, is the new property value after the action.
  224. */
  225. typedef bool
  226. (* JSGetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
  227. JS::MutableHandleValue vp);
  228. /** Add a property named by id to obj. */
  229. typedef bool
  230. (* JSAddPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v);
  231. /**
  232. * Set a property named by id in obj, treating the assignment as strict
  233. * mode code if strict is true. Note the jsid id type -- id may be a string
  234. * (Unicode property identifier) or an int (element index). The *vp out
  235. * parameter, on success, is the new property value after the
  236. * set.
  237. */
  238. typedef bool
  239. (* JSSetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
  240. JS::MutableHandleValue vp, JS::ObjectOpResult& result);
  241. /**
  242. * Delete a property named by id in obj.
  243. *
  244. * If an error occurred, return false as per normal JSAPI error practice.
  245. *
  246. * If no error occurred, but the deletion attempt wasn't allowed (perhaps
  247. * because the property was non-configurable), call result.fail() and
  248. * return true. This will cause |delete obj[id]| to evaluate to false in
  249. * non-strict mode code, and to throw a TypeError in strict mode code.
  250. *
  251. * If no error occurred and the deletion wasn't disallowed (this is *not* the
  252. * same as saying that a deletion actually occurred -- deleting a non-existent
  253. * property, or an inherited property, is allowed -- it's just pointless),
  254. * call result.succeed() and return true.
  255. */
  256. typedef bool
  257. (* JSDeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
  258. JS::ObjectOpResult& result);
  259. /**
  260. * The type of ObjectOps::enumerate. This callback overrides a portion of
  261. * SpiderMonkey's default [[Enumerate]] internal method. When an ordinary object
  262. * is enumerated, that object and each object on its prototype chain is tested
  263. * for an enumerate op, and those ops are called in order. The properties each
  264. * op adds to the 'properties' vector are added to the set of values the for-in
  265. * loop will iterate over. All of this is nonstandard.
  266. *
  267. * An object is "enumerated" when it's the target of a for-in loop or
  268. * JS_Enumerate(). The callback's job is to populate 'properties' with the
  269. * object's property keys. If `enumerableOnly` is true, the callback should only
  270. * add enumerable properties.
  271. */
  272. typedef bool
  273. (* JSNewEnumerateOp)(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
  274. bool enumerableOnly);
  275. /**
  276. * The old-style JSClass.enumerate op should define all lazy properties not
  277. * yet reflected in obj.
  278. */
  279. typedef bool
  280. (* JSEnumerateOp)(JSContext* cx, JS::HandleObject obj);
  281. /**
  282. * The type of ObjectOps::funToString. This callback allows an object to
  283. * provide a custom string to use when Function.prototype.toString is invoked on
  284. * that object. A null return value means OOM.
  285. */
  286. typedef JSString*
  287. (* JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, unsigned indent);
  288. /**
  289. * Resolve a lazy property named by id in obj by defining it directly in obj.
  290. * Lazy properties are those reflected from some peer native property space
  291. * (e.g., the DOM attributes for a given node reflected as obj) on demand.
  292. *
  293. * JS looks for a property in an object, and if not found, tries to resolve
  294. * the given id. *resolvedp should be set to true iff the property was defined
  295. * on |obj|.
  296. */
  297. typedef bool
  298. (* JSResolveOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
  299. bool* resolvedp);
  300. /**
  301. * A class with a resolve hook can optionally have a mayResolve hook. This hook
  302. * must have no side effects and must return true for a given id if the resolve
  303. * hook may resolve this id. This is useful when we're doing a "pure" lookup: if
  304. * mayResolve returns false, we know we don't have to call the effectful resolve
  305. * hook.
  306. *
  307. * maybeObj, if non-null, is the object on which we're doing the lookup. This
  308. * can be nullptr: during JIT compilation we sometimes know the Class but not
  309. * the object.
  310. */
  311. typedef bool
  312. (* JSMayResolveOp)(const JSAtomState& names, jsid id, JSObject* maybeObj);
  313. /**
  314. * Finalize obj, which the garbage collector has determined to be unreachable
  315. * from other live objects or from GC roots. Obviously, finalizers must never
  316. * store a reference to obj.
  317. */
  318. typedef void
  319. (* JSFinalizeOp)(JSFreeOp* fop, JSObject* obj);
  320. /** Finalizes external strings created by JS_NewExternalString. */
  321. struct JSStringFinalizer {
  322. void (*finalize)(JS::Zone* zone, const JSStringFinalizer* fin, char16_t* chars);
  323. };
  324. /**
  325. * Check whether v is an instance of obj. Return false on error or exception,
  326. * true on success with true in *bp if v is an instance of obj, false in
  327. * *bp otherwise.
  328. */
  329. typedef bool
  330. (* JSHasInstanceOp)(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp,
  331. bool* bp);
  332. /**
  333. * Function type for trace operation of the class called to enumerate all
  334. * traceable things reachable from obj's private data structure. For each such
  335. * thing, a trace implementation must call JS::TraceEdge on the thing's
  336. * location.
  337. *
  338. * JSTraceOp implementation can assume that no other threads mutates object
  339. * state. It must not change state of the object or corresponding native
  340. * structures. The only exception for this rule is the case when the embedding
  341. * needs a tight integration with GC. In that case the embedding can check if
  342. * the traversal is a part of the marking phase through calling
  343. * JS_IsGCMarkingTracer and apply a special code like emptying caches or
  344. * marking its native structures.
  345. */
  346. typedef void
  347. (* JSTraceOp)(JSTracer* trc, JSObject* obj);
  348. typedef JSObject*
  349. (* JSWeakmapKeyDelegateOp)(JSObject* obj);
  350. typedef void
  351. (* JSObjectMovedOp)(JSObject* obj, const JSObject* old);
  352. /* js::Class operation signatures. */
  353. namespace js {
  354. typedef bool
  355. (* LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
  356. JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
  357. typedef bool
  358. (* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
  359. JS::Handle<JS::PropertyDescriptor> desc,
  360. JS::ObjectOpResult& result);
  361. typedef bool
  362. (* HasPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
  363. typedef bool
  364. (* GetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id,
  365. JS::MutableHandleValue vp);
  366. typedef bool
  367. (* SetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v,
  368. JS::HandleValue receiver, JS::ObjectOpResult& result);
  369. typedef bool
  370. (* GetOwnPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
  371. JS::MutableHandle<JS::PropertyDescriptor> desc);
  372. typedef bool
  373. (* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
  374. JS::ObjectOpResult& result);
  375. typedef bool
  376. (* WatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
  377. typedef bool
  378. (* UnwatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id);
  379. class JS_FRIEND_API(ElementAdder)
  380. {
  381. public:
  382. enum GetBehavior {
  383. // Check if the element exists before performing the Get and preserve
  384. // holes.
  385. CheckHasElemPreserveHoles,
  386. // Perform a Get operation, like obj[index] in JS.
  387. GetElement
  388. };
  389. private:
  390. // Only one of these is used.
  391. JS::RootedObject resObj_;
  392. JS::Value* vp_;
  393. uint32_t index_;
  394. #ifdef DEBUG
  395. uint32_t length_;
  396. #endif
  397. GetBehavior getBehavior_;
  398. public:
  399. ElementAdder(JSContext* cx, JSObject* obj, uint32_t length, GetBehavior behavior)
  400. : resObj_(cx, obj), vp_(nullptr), index_(0),
  401. #ifdef DEBUG
  402. length_(length),
  403. #endif
  404. getBehavior_(behavior)
  405. {}
  406. ElementAdder(JSContext* cx, JS::Value* vp, uint32_t length, GetBehavior behavior)
  407. : resObj_(cx), vp_(vp), index_(0),
  408. #ifdef DEBUG
  409. length_(length),
  410. #endif
  411. getBehavior_(behavior)
  412. {}
  413. GetBehavior getBehavior() const { return getBehavior_; }
  414. bool append(JSContext* cx, JS::HandleValue v);
  415. void appendHole();
  416. };
  417. typedef bool
  418. (* GetElementsOp)(JSContext* cx, JS::HandleObject obj, uint32_t begin, uint32_t end,
  419. ElementAdder* adder);
  420. typedef void
  421. (* FinalizeOp)(FreeOp* fop, JSObject* obj);
  422. // The special treatment of |finalize| and |trace| is necessary because if we
  423. // assign either of those hooks to a local variable and then call it -- as is
  424. // done with the other hooks -- the GC hazard analysis gets confused.
  425. #define JS_CLASS_MEMBERS(ClassOpsType, FreeOpType) \
  426. const char* name; \
  427. uint32_t flags; \
  428. const ClassOpsType* cOps; \
  429. \
  430. JSAddPropertyOp getAddProperty() const { return cOps ? cOps->addProperty : nullptr; } \
  431. JSDeletePropertyOp getDelProperty() const { return cOps ? cOps->delProperty : nullptr; } \
  432. JSGetterOp getGetProperty() const { return cOps ? cOps->getProperty : nullptr; } \
  433. JSSetterOp getSetProperty() const { return cOps ? cOps->setProperty : nullptr; } \
  434. JSEnumerateOp getEnumerate() const { return cOps ? cOps->enumerate : nullptr; } \
  435. JSResolveOp getResolve() const { return cOps ? cOps->resolve : nullptr; } \
  436. JSMayResolveOp getMayResolve() const { return cOps ? cOps->mayResolve : nullptr; } \
  437. JSNative getCall() const { return cOps ? cOps->call : nullptr; } \
  438. JSHasInstanceOp getHasInstance() const { return cOps ? cOps->hasInstance : nullptr; } \
  439. JSNative getConstruct() const { return cOps ? cOps->construct : nullptr; } \
  440. \
  441. bool hasFinalize() const { return cOps && cOps->finalize; } \
  442. bool hasTrace() const { return cOps && cOps->trace; } \
  443. \
  444. bool isTrace(JSTraceOp trace) const { return cOps && cOps->trace == trace; } \
  445. \
  446. void doFinalize(FreeOpType* fop, JSObject* obj) const { \
  447. MOZ_ASSERT(cOps && cOps->finalize); \
  448. cOps->finalize(fop, obj); \
  449. } \
  450. void doTrace(JSTracer* trc, JSObject* obj) const { \
  451. MOZ_ASSERT(cOps && cOps->trace); \
  452. cOps->trace(trc, obj); \
  453. }
  454. struct ClassOps
  455. {
  456. /* Function pointer members (may be null). */
  457. JSAddPropertyOp addProperty;
  458. JSDeletePropertyOp delProperty;
  459. JSGetterOp getProperty;
  460. JSSetterOp setProperty;
  461. JSEnumerateOp enumerate;
  462. JSResolveOp resolve;
  463. JSMayResolveOp mayResolve;
  464. FinalizeOp finalize;
  465. JSNative call;
  466. JSHasInstanceOp hasInstance;
  467. JSNative construct;
  468. JSTraceOp trace;
  469. };
  470. /** Callback for the creation of constructor and prototype objects. */
  471. typedef JSObject* (*ClassObjectCreationOp)(JSContext* cx, JSProtoKey key);
  472. /** Callback for custom post-processing after class initialization via ClassSpec. */
  473. typedef bool (*FinishClassInitOp)(JSContext* cx, JS::HandleObject ctor,
  474. JS::HandleObject proto);
  475. const size_t JSCLASS_CACHED_PROTO_WIDTH = 6;
  476. struct ClassSpec
  477. {
  478. // All properties except flags should be accessed through accessor.
  479. ClassObjectCreationOp createConstructor_;
  480. ClassObjectCreationOp createPrototype_;
  481. const JSFunctionSpec* constructorFunctions_;
  482. const JSPropertySpec* constructorProperties_;
  483. const JSFunctionSpec* prototypeFunctions_;
  484. const JSPropertySpec* prototypeProperties_;
  485. FinishClassInitOp finishInit_;
  486. uintptr_t flags;
  487. static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH;
  488. static const uintptr_t ProtoKeyMask = (1 << ProtoKeyWidth) - 1;
  489. static const uintptr_t DontDefineConstructor = 1 << ProtoKeyWidth;
  490. static const uintptr_t IsDelegated = 1 << (ProtoKeyWidth + 1);
  491. bool defined() const { return !!createConstructor_; }
  492. bool delegated() const {
  493. return (flags & IsDelegated);
  494. }
  495. // The ProtoKey this class inherits from.
  496. JSProtoKey inheritanceProtoKey() const {
  497. MOZ_ASSERT(defined());
  498. static_assert(JSProto_Null == 0, "zeroed key must be null");
  499. // Default: Inherit from Object.
  500. if (!(flags & ProtoKeyMask))
  501. return JSProto_Object;
  502. return JSProtoKey(flags & ProtoKeyMask);
  503. }
  504. bool shouldDefineConstructor() const {
  505. MOZ_ASSERT(defined());
  506. return !(flags & DontDefineConstructor);
  507. }
  508. const ClassSpec* delegatedClassSpec() const {
  509. MOZ_ASSERT(delegated());
  510. return reinterpret_cast<ClassSpec*>(createConstructor_);
  511. }
  512. ClassObjectCreationOp createConstructorHook() const {
  513. if (delegated())
  514. return delegatedClassSpec()->createConstructorHook();
  515. return createConstructor_;
  516. }
  517. ClassObjectCreationOp createPrototypeHook() const {
  518. if (delegated())
  519. return delegatedClassSpec()->createPrototypeHook();
  520. return createPrototype_;
  521. }
  522. const JSFunctionSpec* constructorFunctions() const {
  523. if (delegated())
  524. return delegatedClassSpec()->constructorFunctions();
  525. return constructorFunctions_;
  526. }
  527. const JSPropertySpec* constructorProperties() const {
  528. if (delegated())
  529. return delegatedClassSpec()->constructorProperties();
  530. return constructorProperties_;
  531. }
  532. const JSFunctionSpec* prototypeFunctions() const {
  533. if (delegated())
  534. return delegatedClassSpec()->prototypeFunctions();
  535. return prototypeFunctions_;
  536. }
  537. const JSPropertySpec* prototypeProperties() const {
  538. if (delegated())
  539. return delegatedClassSpec()->prototypeProperties();
  540. return prototypeProperties_;
  541. }
  542. FinishClassInitOp finishInitHook() const {
  543. if (delegated())
  544. return delegatedClassSpec()->finishInitHook();
  545. return finishInit_;
  546. }
  547. };
  548. struct ClassExtension
  549. {
  550. /**
  551. * If an object is used as a key in a weakmap, it may be desirable for the
  552. * garbage collector to keep that object around longer than it otherwise
  553. * would. A common case is when the key is a wrapper around an object in
  554. * another compartment, and we want to avoid collecting the wrapper (and
  555. * removing the weakmap entry) as long as the wrapped object is alive. In
  556. * that case, the wrapped object is returned by the wrapper's
  557. * weakmapKeyDelegateOp hook. As long as the wrapper is used as a weakmap
  558. * key, it will not be collected (and remain in the weakmap) until the
  559. * wrapped object is collected.
  560. */
  561. JSWeakmapKeyDelegateOp weakmapKeyDelegateOp;
  562. /**
  563. * Optional hook called when an object is moved by a compacting GC.
  564. *
  565. * There may exist weak pointers to an object that are not traced through
  566. * when the normal trace APIs are used, for example objects in the wrapper
  567. * cache. This hook allows these pointers to be updated.
  568. *
  569. * Note that this hook can be called before JS_NewObject() returns if a GC
  570. * is triggered during construction of the object. This can happen for
  571. * global objects for example.
  572. */
  573. JSObjectMovedOp objectMovedOp;
  574. };
  575. inline ClassObjectCreationOp DELEGATED_CLASSSPEC(const ClassSpec* spec) {
  576. return reinterpret_cast<ClassObjectCreationOp>(const_cast<ClassSpec*>(spec));
  577. }
  578. #define JS_NULL_CLASS_SPEC nullptr
  579. #define JS_NULL_CLASS_EXT nullptr
  580. struct ObjectOps
  581. {
  582. LookupPropertyOp lookupProperty;
  583. DefinePropertyOp defineProperty;
  584. HasPropertyOp hasProperty;
  585. GetPropertyOp getProperty;
  586. SetPropertyOp setProperty;
  587. GetOwnPropertyOp getOwnPropertyDescriptor;
  588. DeletePropertyOp deleteProperty;
  589. WatchOp watch;
  590. UnwatchOp unwatch;
  591. GetElementsOp getElements;
  592. JSNewEnumerateOp enumerate;
  593. JSFunToStringOp funToString;
  594. };
  595. #define JS_NULL_OBJECT_OPS nullptr
  596. } // namespace js
  597. // Classes, objects, and properties.
  598. typedef void (*JSClassInternal)();
  599. struct JSClassOps
  600. {
  601. /* Function pointer members (may be null). */
  602. JSAddPropertyOp addProperty;
  603. JSDeletePropertyOp delProperty;
  604. JSGetterOp getProperty;
  605. JSSetterOp setProperty;
  606. JSEnumerateOp enumerate;
  607. JSResolveOp resolve;
  608. JSMayResolveOp mayResolve;
  609. JSFinalizeOp finalize;
  610. JSNative call;
  611. JSHasInstanceOp hasInstance;
  612. JSNative construct;
  613. JSTraceOp trace;
  614. };
  615. #define JS_NULL_CLASS_OPS nullptr
  616. struct JSClass {
  617. JS_CLASS_MEMBERS(JSClassOps, JSFreeOp);
  618. void* reserved[3];
  619. };
  620. #define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot
  621. #define JSCLASS_DELAY_METADATA_BUILDER (1<<1) // class's initialization code
  622. // will call
  623. // SetNewObjectMetadata itself
  624. #define JSCLASS_IS_WRAPPED_NATIVE (1<<2) // class is an XPCWrappedNative.
  625. // WeakMaps use this to override
  626. // the wrapper disposal
  627. // mechanism.
  628. #define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) // private is (nsISupports*)
  629. #define JSCLASS_IS_DOMJSCLASS (1<<4) // objects are DOM
  630. #define JSCLASS_HAS_XRAYED_CONSTRUCTOR (1<<5) // if wrapped by an xray
  631. // wrapper, the builtin
  632. // class's constructor won't
  633. // be unwrapped and invoked.
  634. // Instead, the constructor is
  635. // resolved in the caller's
  636. // compartment and invoked
  637. // with a wrapped newTarget.
  638. // The constructor has to
  639. // detect and handle this
  640. // situation.
  641. // See PromiseConstructor for
  642. // details.
  643. #define JSCLASS_EMULATES_UNDEFINED (1<<6) // objects of this class act
  644. // like the value undefined,
  645. // in some contexts
  646. #define JSCLASS_USERBIT1 (1<<7) // Reserved for embeddings.
  647. // To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
  648. // JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where
  649. // n is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1.
  650. #define JSCLASS_RESERVED_SLOTS_SHIFT 8 // room for 8 flags below */
  651. #define JSCLASS_RESERVED_SLOTS_WIDTH 8 // and 16 above this field */
  652. #define JSCLASS_RESERVED_SLOTS_MASK JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH)
  653. #define JSCLASS_HAS_RESERVED_SLOTS(n) (((n) & JSCLASS_RESERVED_SLOTS_MASK) \
  654. << JSCLASS_RESERVED_SLOTS_SHIFT)
  655. #define JSCLASS_RESERVED_SLOTS(clasp) (((clasp)->flags \
  656. >> JSCLASS_RESERVED_SLOTS_SHIFT) \
  657. & JSCLASS_RESERVED_SLOTS_MASK)
  658. #define JSCLASS_HIGH_FLAGS_SHIFT (JSCLASS_RESERVED_SLOTS_SHIFT + \
  659. JSCLASS_RESERVED_SLOTS_WIDTH)
  660. #define JSCLASS_IS_ANONYMOUS (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0))
  661. #define JSCLASS_IS_GLOBAL (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1))
  662. #define JSCLASS_INTERNAL_FLAG2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2))
  663. #define JSCLASS_INTERNAL_FLAG3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3))
  664. #define JSCLASS_IS_PROXY (1<<(JSCLASS_HIGH_FLAGS_SHIFT+4))
  665. #define JSCLASS_SKIP_NURSERY_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+5))
  666. // Reserved for embeddings.
  667. #define JSCLASS_USERBIT2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6))
  668. #define JSCLASS_USERBIT3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7))
  669. #define JSCLASS_BACKGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+8))
  670. #define JSCLASS_FOREGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+9))
  671. // Bits 26 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see
  672. // below.
  673. // ECMA-262 requires that most constructors used internally create objects
  674. // with "the original Foo.prototype value" as their [[Prototype]] (__proto__)
  675. // member initial value. The "original ... value" verbiage is there because
  676. // in ECMA-262, global properties naming class objects are read/write and
  677. // deleteable, for the most part.
  678. //
  679. // Implementing this efficiently requires that global objects have classes
  680. // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
  681. // previously allowed, but is now an ES5 violation and thus unsupported.
  682. //
  683. // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
  684. // the beginning of every global object's slots for use by the
  685. // application.
  686. #define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
  687. #define JSCLASS_GLOBAL_SLOT_COUNT \
  688. (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 39)
  689. #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
  690. (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
  691. #define JSCLASS_GLOBAL_FLAGS \
  692. JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
  693. #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \
  694. (((clasp)->flags & JSCLASS_IS_GLOBAL) \
  695. && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
  696. // Fast access to the original value of each standard class's prototype.
  697. #define JSCLASS_CACHED_PROTO_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT + 10)
  698. #define JSCLASS_CACHED_PROTO_MASK JS_BITMASK(js::JSCLASS_CACHED_PROTO_WIDTH)
  699. #define JSCLASS_HAS_CACHED_PROTO(key) (uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT)
  700. #define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey) \
  701. (((clasp)->flags \
  702. >> JSCLASS_CACHED_PROTO_SHIFT) \
  703. & JSCLASS_CACHED_PROTO_MASK))
  704. // Initializer for unused members of statically initialized JSClass structs.
  705. #define JSCLASS_NO_INTERNAL_MEMBERS {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  706. #define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS
  707. namespace js {
  708. struct Class
  709. {
  710. JS_CLASS_MEMBERS(js::ClassOps, FreeOp);
  711. const ClassSpec* spec;
  712. const ClassExtension* ext;
  713. const ObjectOps* oOps;
  714. /*
  715. * Objects of this class aren't native objects. They don't have Shapes that
  716. * describe their properties and layout. Classes using this flag must
  717. * provide their own property behavior, either by being proxy classes (do
  718. * this) or by overriding all the ObjectOps except getElements, watch and
  719. * unwatch (don't do this).
  720. */
  721. static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
  722. bool isNative() const {
  723. return !(flags & NON_NATIVE);
  724. }
  725. bool hasPrivate() const {
  726. return !!(flags & JSCLASS_HAS_PRIVATE);
  727. }
  728. bool emulatesUndefined() const {
  729. return flags & JSCLASS_EMULATES_UNDEFINED;
  730. }
  731. bool isJSFunction() const {
  732. return this == js::FunctionClassPtr;
  733. }
  734. bool nonProxyCallable() const {
  735. MOZ_ASSERT(!isProxy());
  736. return isJSFunction() || getCall();
  737. }
  738. bool isProxy() const {
  739. return flags & JSCLASS_IS_PROXY;
  740. }
  741. bool isDOMClass() const {
  742. return flags & JSCLASS_IS_DOMJSCLASS;
  743. }
  744. bool shouldDelayMetadataBuilder() const {
  745. return flags & JSCLASS_DELAY_METADATA_BUILDER;
  746. }
  747. bool isWrappedNative() const {
  748. return flags & JSCLASS_IS_WRAPPED_NATIVE;
  749. }
  750. static size_t offsetOfFlags() { return offsetof(Class, flags); }
  751. bool specDefined() const { return spec ? spec->defined() : false; }
  752. JSProtoKey specInheritanceProtoKey()
  753. const { return spec ? spec->inheritanceProtoKey() : JSProto_Null; }
  754. bool specShouldDefineConstructor()
  755. const { return spec ? spec->shouldDefineConstructor() : true; }
  756. ClassObjectCreationOp specCreateConstructorHook()
  757. const { return spec ? spec->createConstructorHook() : nullptr; }
  758. ClassObjectCreationOp specCreatePrototypeHook()
  759. const { return spec ? spec->createPrototypeHook() : nullptr; }
  760. const JSFunctionSpec* specConstructorFunctions()
  761. const { return spec ? spec->constructorFunctions() : nullptr; }
  762. const JSPropertySpec* specConstructorProperties()
  763. const { return spec ? spec->constructorProperties() : nullptr; }
  764. const JSFunctionSpec* specPrototypeFunctions()
  765. const { return spec ? spec->prototypeFunctions() : nullptr; }
  766. const JSPropertySpec* specPrototypeProperties()
  767. const { return spec ? spec->prototypeProperties() : nullptr; }
  768. FinishClassInitOp specFinishInitHook()
  769. const { return spec ? spec->finishInitHook() : nullptr; }
  770. JSWeakmapKeyDelegateOp extWeakmapKeyDelegateOp()
  771. const { return ext ? ext->weakmapKeyDelegateOp : nullptr; }
  772. JSObjectMovedOp extObjectMovedOp()
  773. const { return ext ? ext->objectMovedOp : nullptr; }
  774. LookupPropertyOp getOpsLookupProperty() const { return oOps ? oOps->lookupProperty : nullptr; }
  775. DefinePropertyOp getOpsDefineProperty() const { return oOps ? oOps->defineProperty : nullptr; }
  776. HasPropertyOp getOpsHasProperty() const { return oOps ? oOps->hasProperty : nullptr; }
  777. GetPropertyOp getOpsGetProperty() const { return oOps ? oOps->getProperty : nullptr; }
  778. SetPropertyOp getOpsSetProperty() const { return oOps ? oOps->setProperty : nullptr; }
  779. GetOwnPropertyOp getOpsGetOwnPropertyDescriptor()
  780. const { return oOps ? oOps->getOwnPropertyDescriptor
  781. : nullptr; }
  782. DeletePropertyOp getOpsDeleteProperty() const { return oOps ? oOps->deleteProperty : nullptr; }
  783. WatchOp getOpsWatch() const { return oOps ? oOps->watch : nullptr; }
  784. UnwatchOp getOpsUnwatch() const { return oOps ? oOps->unwatch : nullptr; }
  785. GetElementsOp getOpsGetElements() const { return oOps ? oOps->getElements : nullptr; }
  786. JSNewEnumerateOp getOpsEnumerate() const { return oOps ? oOps->enumerate : nullptr; }
  787. JSFunToStringOp getOpsFunToString() const { return oOps ? oOps->funToString : nullptr; }
  788. };
  789. static_assert(offsetof(JSClassOps, addProperty) == offsetof(ClassOps, addProperty),
  790. "ClassOps and JSClassOps must be consistent");
  791. static_assert(offsetof(JSClassOps, delProperty) == offsetof(ClassOps, delProperty),
  792. "ClassOps and JSClassOps must be consistent");
  793. static_assert(offsetof(JSClassOps, getProperty) == offsetof(ClassOps, getProperty),
  794. "ClassOps and JSClassOps must be consistent");
  795. static_assert(offsetof(JSClassOps, setProperty) == offsetof(ClassOps, setProperty),
  796. "ClassOps and JSClassOps must be consistent");
  797. static_assert(offsetof(JSClassOps, enumerate) == offsetof(ClassOps, enumerate),
  798. "ClassOps and JSClassOps must be consistent");
  799. static_assert(offsetof(JSClassOps, resolve) == offsetof(ClassOps, resolve),
  800. "ClassOps and JSClassOps must be consistent");
  801. static_assert(offsetof(JSClassOps, mayResolve) == offsetof(ClassOps, mayResolve),
  802. "ClassOps and JSClassOps must be consistent");
  803. static_assert(offsetof(JSClassOps, finalize) == offsetof(ClassOps, finalize),
  804. "ClassOps and JSClassOps must be consistent");
  805. static_assert(offsetof(JSClassOps, call) == offsetof(ClassOps, call),
  806. "ClassOps and JSClassOps must be consistent");
  807. static_assert(offsetof(JSClassOps, construct) == offsetof(ClassOps, construct),
  808. "ClassOps and JSClassOps must be consistent");
  809. static_assert(offsetof(JSClassOps, hasInstance) == offsetof(ClassOps, hasInstance),
  810. "ClassOps and JSClassOps must be consistent");
  811. static_assert(offsetof(JSClassOps, trace) == offsetof(ClassOps, trace),
  812. "ClassOps and JSClassOps must be consistent");
  813. static_assert(sizeof(JSClassOps) == sizeof(ClassOps),
  814. "ClassOps and JSClassOps must be consistent");
  815. static_assert(offsetof(JSClass, name) == offsetof(Class, name),
  816. "Class and JSClass must be consistent");
  817. static_assert(offsetof(JSClass, flags) == offsetof(Class, flags),
  818. "Class and JSClass must be consistent");
  819. static_assert(offsetof(JSClass, cOps) == offsetof(Class, cOps),
  820. "Class and JSClass must be consistent");
  821. static_assert(sizeof(JSClass) == sizeof(Class),
  822. "Class and JSClass must be consistent");
  823. static MOZ_ALWAYS_INLINE const JSClass*
  824. Jsvalify(const Class* c)
  825. {
  826. return (const JSClass*)c;
  827. }
  828. static MOZ_ALWAYS_INLINE const Class*
  829. Valueify(const JSClass* c)
  830. {
  831. return (const Class*)c;
  832. }
  833. /**
  834. * Enumeration describing possible values of the [[Class]] internal property
  835. * value of objects.
  836. */
  837. enum class ESClass {
  838. Object,
  839. Array,
  840. Number,
  841. String,
  842. Boolean,
  843. RegExp,
  844. ArrayBuffer,
  845. SharedArrayBuffer,
  846. Date,
  847. Set,
  848. Map,
  849. Promise,
  850. MapIterator,
  851. SetIterator,
  852. Arguments,
  853. Error,
  854. /** None of the above. */
  855. Other
  856. };
  857. /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */
  858. bool
  859. Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp);
  860. #ifdef DEBUG
  861. JS_FRIEND_API(bool)
  862. HasObjectMovedOp(JSObject* obj);
  863. #endif
  864. } /* namespace js */
  865. #endif /* js_Class_h */