Value.h 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509
  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. /* JS::Value implementation. */
  7. #ifndef js_Value_h
  8. #define js_Value_h
  9. #include "mozilla/Attributes.h"
  10. #include "mozilla/Casting.h"
  11. #include "mozilla/FloatingPoint.h"
  12. #include "mozilla/Likely.h"
  13. #include <limits> /* for std::numeric_limits */
  14. #include "js-config.h"
  15. #include "jstypes.h"
  16. #include "js/GCAPI.h"
  17. #include "js/RootingAPI.h"
  18. #include "js/Utility.h"
  19. namespace JS { class Value; }
  20. /* JS::Value can store a full int32_t. */
  21. #define JSVAL_INT_BITS 32
  22. #define JSVAL_INT_MIN ((int32_t)0x80000000)
  23. #define JSVAL_INT_MAX ((int32_t)0x7fffffff)
  24. #if defined(JS_PUNBOX64)
  25. # define JSVAL_TAG_SHIFT 47
  26. #endif
  27. // Use enums so that printing a JS::Value in the debugger shows nice
  28. // symbolic type tags.
  29. #if defined(_MSC_VER)
  30. # define JS_ENUM_HEADER(id, type) enum id : type
  31. # define JS_ENUM_FOOTER(id)
  32. #else
  33. # define JS_ENUM_HEADER(id, type) enum id
  34. # define JS_ENUM_FOOTER(id) __attribute__((packed))
  35. #endif
  36. /* Remember to propagate changes to the C defines below. */
  37. JS_ENUM_HEADER(JSValueType, uint8_t)
  38. {
  39. JSVAL_TYPE_DOUBLE = 0x00,
  40. JSVAL_TYPE_INT32 = 0x01,
  41. JSVAL_TYPE_UNDEFINED = 0x02,
  42. JSVAL_TYPE_BOOLEAN = 0x03,
  43. JSVAL_TYPE_MAGIC = 0x04,
  44. JSVAL_TYPE_STRING = 0x05,
  45. JSVAL_TYPE_SYMBOL = 0x06,
  46. JSVAL_TYPE_PRIVATE_GCTHING = 0x07,
  47. JSVAL_TYPE_NULL = 0x08,
  48. JSVAL_TYPE_OBJECT = 0x0c,
  49. /* These never appear in a jsval; they are only provided as an out-of-band value. */
  50. JSVAL_TYPE_UNKNOWN = 0x20,
  51. JSVAL_TYPE_MISSING = 0x21
  52. } JS_ENUM_FOOTER(JSValueType);
  53. static_assert(sizeof(JSValueType) == 1,
  54. "compiler typed enum support is apparently buggy");
  55. #if defined(JS_NUNBOX32)
  56. /* Remember to propagate changes to the C defines below. */
  57. JS_ENUM_HEADER(JSValueTag, uint32_t)
  58. {
  59. JSVAL_TAG_CLEAR = 0xFFFFFF80,
  60. JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
  61. JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
  62. JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
  63. JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
  64. JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
  65. JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
  66. JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
  67. JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT,
  68. JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING
  69. } JS_ENUM_FOOTER(JSValueTag);
  70. static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
  71. "compiler typed enum support is apparently buggy");
  72. #elif defined(JS_PUNBOX64)
  73. /* Remember to propagate changes to the C defines below. */
  74. JS_ENUM_HEADER(JSValueTag, uint32_t)
  75. {
  76. JSVAL_TAG_MAX_DOUBLE = 0x1FFF0,
  77. JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
  78. JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
  79. JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
  80. JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
  81. JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
  82. JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
  83. JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
  84. JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT,
  85. JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING
  86. } JS_ENUM_FOOTER(JSValueTag);
  87. static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
  88. "compiler typed enum support is apparently buggy");
  89. JS_ENUM_HEADER(JSValueShiftedTag, uint64_t)
  90. {
  91. JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
  92. JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT),
  93. JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT),
  94. JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT),
  95. JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT),
  96. JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT),
  97. JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT),
  98. JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT),
  99. JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT),
  100. JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT)
  101. } JS_ENUM_FOOTER(JSValueShiftedTag);
  102. static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
  103. "compiler typed enum support is apparently buggy");
  104. #endif
  105. /*
  106. * All our supported compilers implement C++11 |enum Foo : T| syntax, so don't
  107. * expose these macros. (This macro exists *only* because gcc bug 51242
  108. * <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51242> makes bit-fields of
  109. * typed enums trigger a warning that can't be turned off. Don't expose it
  110. * beyond this file!)
  111. */
  112. #undef JS_ENUM_HEADER
  113. #undef JS_ENUM_FOOTER
  114. #if defined(JS_NUNBOX32)
  115. #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type)))
  116. #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL
  117. #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT
  118. #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32
  119. #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING
  120. #elif defined(JS_PUNBOX64)
  121. #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL
  122. #define JSVAL_TAG_MASK 0xFFFF800000000000LL
  123. #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type)))
  124. #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT)
  125. #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL
  126. #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT
  127. #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32
  128. #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING
  129. #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL
  130. #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT
  131. #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED
  132. #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING
  133. #endif /* JS_PUNBOX64 */
  134. typedef enum JSWhyMagic
  135. {
  136. /** a hole in a native object's elements */
  137. JS_ELEMENTS_HOLE,
  138. /** there is not a pending iterator value */
  139. JS_NO_ITER_VALUE,
  140. /** exception value thrown when closing a generator */
  141. JS_GENERATOR_CLOSING,
  142. /** compiler sentinel value */
  143. JS_NO_CONSTANT,
  144. /** used in debug builds to catch tracing errors */
  145. JS_THIS_POISON,
  146. /** used in debug builds to catch tracing errors */
  147. JS_ARG_POISON,
  148. /** an empty subnode in the AST serializer */
  149. JS_SERIALIZE_NO_NODE,
  150. /** lazy arguments value on the stack */
  151. JS_LAZY_ARGUMENTS,
  152. /** optimized-away 'arguments' value */
  153. JS_OPTIMIZED_ARGUMENTS,
  154. /** magic value passed to natives to indicate construction */
  155. JS_IS_CONSTRUCTING,
  156. /** value of static block object slot */
  157. JS_BLOCK_NEEDS_CLONE,
  158. /** see class js::HashableValue */
  159. JS_HASH_KEY_EMPTY,
  160. /** error while running Ion code */
  161. JS_ION_ERROR,
  162. /** missing recover instruction result */
  163. JS_ION_BAILOUT,
  164. /** optimized out slot */
  165. JS_OPTIMIZED_OUT,
  166. /** uninitialized lexical bindings that produce ReferenceError on touch. */
  167. JS_UNINITIALIZED_LEXICAL,
  168. /** for local use */
  169. JS_GENERIC_MAGIC,
  170. JS_WHY_MAGIC_COUNT
  171. } JSWhyMagic;
  172. namespace JS {
  173. static inline constexpr JS::Value UndefinedValue();
  174. static inline JS::Value PoisonedObjectValue(JSObject* obj);
  175. namespace detail {
  176. constexpr int CanonicalizedNaNSignBit = 0;
  177. constexpr uint64_t CanonicalizedNaNSignificand = 0x8000000000000ULL;
  178. constexpr uint64_t CanonicalizedNaNBits =
  179. mozilla::SpecificNaNBits<double,
  180. detail::CanonicalizedNaNSignBit,
  181. detail::CanonicalizedNaNSignificand>::value;
  182. } // namespace detail
  183. /**
  184. * Returns a generic quiet NaN value, with all payload bits set to zero.
  185. *
  186. * Among other properties, this NaN's bit pattern conforms to JS::Value's
  187. * bit pattern restrictions.
  188. */
  189. static MOZ_ALWAYS_INLINE double
  190. GenericNaN()
  191. {
  192. return mozilla::SpecificNaN<double>(detail::CanonicalizedNaNSignBit,
  193. detail::CanonicalizedNaNSignificand);
  194. }
  195. /* MSVC with PGO miscompiles this function. */
  196. #if defined(_MSC_VER)
  197. # pragma optimize("g", off)
  198. #endif
  199. static inline double
  200. CanonicalizeNaN(double d)
  201. {
  202. if (MOZ_UNLIKELY(mozilla::IsNaN(d)))
  203. return GenericNaN();
  204. return d;
  205. }
  206. #if defined(_MSC_VER)
  207. # pragma optimize("", on)
  208. #endif
  209. /**
  210. * JS::Value is the interface for a single JavaScript Engine value. A few
  211. * general notes on JS::Value:
  212. *
  213. * - JS::Value has setX() and isX() members for X in
  214. *
  215. * { Int32, Double, String, Symbol, Boolean, Undefined, Null, Object, Magic }
  216. *
  217. * JS::Value also contains toX() for each of the non-singleton types.
  218. *
  219. * - Magic is a singleton type whose payload contains either a JSWhyMagic "reason" for
  220. * the magic value or a uint32_t value. By providing JSWhyMagic values when
  221. * creating and checking for magic values, it is possible to assert, at
  222. * runtime, that only magic values with the expected reason flow through a
  223. * particular value. For example, if cx->exception has a magic value, the
  224. * reason must be JS_GENERATOR_CLOSING.
  225. *
  226. * - The JS::Value operations are preferred. The JSVAL_* operations remain for
  227. * compatibility; they may be removed at some point. These operations mostly
  228. * provide similar functionality. But there are a few key differences. One
  229. * is that JS::Value gives null a separate type.
  230. * Also, to help prevent mistakenly boxing a nullable JSObject* as an object,
  231. * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a
  232. * JSObject&.) A convenience member Value::setObjectOrNull is provided.
  233. *
  234. * - JSVAL_VOID is the same as the singleton value of the Undefined type.
  235. *
  236. * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on
  237. * 32-bit user code should avoid copying jsval/JS::Value as much as possible,
  238. * preferring to pass by const Value&.
  239. */
  240. class MOZ_NON_PARAM alignas(8) Value
  241. {
  242. public:
  243. #if defined(JS_NUNBOX32)
  244. using PayloadType = uint32_t;
  245. #elif defined(JS_PUNBOX64)
  246. using PayloadType = uint64_t;
  247. #endif
  248. /*
  249. * N.B. the default constructor leaves Value unitialized. Adding a default
  250. * constructor prevents Value from being stored in a union.
  251. */
  252. Value() = default;
  253. Value(const Value& v) = default;
  254. /**
  255. * Returns false if creating a NumberValue containing the given type would
  256. * be lossy, true otherwise.
  257. */
  258. template <typename T>
  259. static bool isNumberRepresentable(const T t) {
  260. return T(double(t)) == t;
  261. }
  262. /*** Mutators ***/
  263. void setNull() {
  264. data.asBits = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0);
  265. }
  266. void setUndefined() {
  267. data.asBits = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
  268. }
  269. void setInt32(int32_t i) {
  270. data.asBits = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
  271. }
  272. int32_t& getInt32Ref() {
  273. MOZ_ASSERT(isInt32());
  274. return data.s.payload.i32;
  275. }
  276. void setDouble(double d) {
  277. // Don't assign to data.asDouble to fix a miscompilation with
  278. // GCC 5.2.1 and 5.3.1. See bug 1312488.
  279. data = layout(d);
  280. MOZ_ASSERT(isDouble());
  281. }
  282. void setNaN() {
  283. setDouble(GenericNaN());
  284. }
  285. double& getDoubleRef() {
  286. MOZ_ASSERT(isDouble());
  287. return data.asDouble;
  288. }
  289. void setString(JSString* str) {
  290. MOZ_ASSERT(uintptr_t(str) > 0x1000);
  291. data.asBits = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str));
  292. }
  293. void setSymbol(JS::Symbol* sym) {
  294. MOZ_ASSERT(uintptr_t(sym) > 0x1000);
  295. data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym));
  296. }
  297. void setObject(JSObject& obj) {
  298. MOZ_ASSERT(uintptr_t(&obj) > 0x1000 || uintptr_t(&obj) == 0x48);
  299. #if defined(JS_PUNBOX64)
  300. // VisualStudio cannot contain parenthesized C++ style cast and shift
  301. // inside decltype in template parameter:
  302. // AssertionConditionType<decltype((uintptr_t(x) >> 1))>
  303. // It throws syntax error.
  304. MOZ_ASSERT((((uintptr_t)&obj) >> JSVAL_TAG_SHIFT) == 0);
  305. #endif
  306. setObjectNoCheck(&obj);
  307. }
  308. private:
  309. void setObjectNoCheck(JSObject* obj) {
  310. data.asBits = bitsFromTagAndPayload(JSVAL_TAG_OBJECT, PayloadType(obj));
  311. }
  312. friend inline Value PoisonedObjectValue(JSObject* obj);
  313. public:
  314. void setBoolean(bool b) {
  315. data.asBits = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b));
  316. }
  317. void setMagic(JSWhyMagic why) {
  318. data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why));
  319. }
  320. void setMagicUint32(uint32_t payload) {
  321. data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload);
  322. }
  323. bool setNumber(uint32_t ui) {
  324. if (ui > JSVAL_INT_MAX) {
  325. setDouble((double)ui);
  326. return false;
  327. } else {
  328. setInt32((int32_t)ui);
  329. return true;
  330. }
  331. }
  332. bool setNumber(double d) {
  333. int32_t i;
  334. if (mozilla::NumberIsInt32(d, &i)) {
  335. setInt32(i);
  336. return true;
  337. }
  338. setDouble(d);
  339. return false;
  340. }
  341. void setObjectOrNull(JSObject* arg) {
  342. if (arg)
  343. setObject(*arg);
  344. else
  345. setNull();
  346. }
  347. void swap(Value& rhs) {
  348. uint64_t tmp = rhs.data.asBits;
  349. rhs.data.asBits = data.asBits;
  350. data.asBits = tmp;
  351. }
  352. private:
  353. JSValueTag toTag() const {
  354. #if defined(JS_NUNBOX32)
  355. return data.s.tag;
  356. #elif defined(JS_PUNBOX64)
  357. return JSValueTag(data.asBits >> JSVAL_TAG_SHIFT);
  358. #endif
  359. }
  360. public:
  361. /*** JIT-only interfaces to interact with and create raw Values ***/
  362. #if defined(JS_NUNBOX32)
  363. PayloadType toNunboxPayload() const {
  364. return data.s.payload.i32;
  365. }
  366. JSValueTag toNunboxTag() const {
  367. return data.s.tag;
  368. }
  369. #elif defined(JS_PUNBOX64)
  370. const void* bitsAsPunboxPointer() const {
  371. return reinterpret_cast<void*>(data.asBits);
  372. }
  373. #endif
  374. /*** Value type queries ***/
  375. /*
  376. * N.B. GCC, in some but not all cases, chooses to emit signed comparison
  377. * of JSValueTag even though its underlying type has been forced to be
  378. * uint32_t. Thus, all comparisons should explicitly cast operands to
  379. * uint32_t.
  380. */
  381. bool isUndefined() const {
  382. #if defined(JS_NUNBOX32)
  383. return toTag() == JSVAL_TAG_UNDEFINED;
  384. #elif defined(JS_PUNBOX64)
  385. return data.asBits == JSVAL_SHIFTED_TAG_UNDEFINED;
  386. #endif
  387. }
  388. bool isNull() const {
  389. #if defined(JS_NUNBOX32)
  390. return toTag() == JSVAL_TAG_NULL;
  391. #elif defined(JS_PUNBOX64)
  392. return data.asBits == JSVAL_SHIFTED_TAG_NULL;
  393. #endif
  394. }
  395. bool isNullOrUndefined() const {
  396. return isNull() || isUndefined();
  397. }
  398. bool isInt32() const {
  399. return toTag() == JSVAL_TAG_INT32;
  400. }
  401. bool isInt32(int32_t i32) const {
  402. return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32));
  403. }
  404. bool isDouble() const {
  405. #if defined(JS_NUNBOX32)
  406. return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR);
  407. #elif defined(JS_PUNBOX64)
  408. return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
  409. #endif
  410. }
  411. bool isNumber() const {
  412. #if defined(JS_NUNBOX32)
  413. MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR);
  414. return uint32_t(toTag()) <= uint32_t(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET);
  415. #elif defined(JS_PUNBOX64)
  416. return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET;
  417. #endif
  418. }
  419. bool isString() const {
  420. return toTag() == JSVAL_TAG_STRING;
  421. }
  422. bool isSymbol() const {
  423. return toTag() == JSVAL_TAG_SYMBOL;
  424. }
  425. bool isObject() const {
  426. #if defined(JS_NUNBOX32)
  427. return toTag() == JSVAL_TAG_OBJECT;
  428. #elif defined(JS_PUNBOX64)
  429. MOZ_ASSERT((data.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
  430. return data.asBits >= JSVAL_SHIFTED_TAG_OBJECT;
  431. #endif
  432. }
  433. bool isPrimitive() const {
  434. #if defined(JS_NUNBOX32)
  435. return uint32_t(toTag()) < uint32_t(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET);
  436. #elif defined(JS_PUNBOX64)
  437. return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET;
  438. #endif
  439. }
  440. bool isObjectOrNull() const {
  441. MOZ_ASSERT(uint32_t(toTag()) <= uint32_t(JSVAL_TAG_OBJECT));
  442. #if defined(JS_NUNBOX32)
  443. return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET);
  444. #elif defined(JS_PUNBOX64)
  445. return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET;
  446. #endif
  447. }
  448. bool isGCThing() const {
  449. #if defined(JS_NUNBOX32)
  450. /* gcc sometimes generates signed < without explicit casts. */
  451. return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET);
  452. #elif defined(JS_PUNBOX64)
  453. return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET;
  454. #endif
  455. }
  456. bool isBoolean() const {
  457. return toTag() == JSVAL_TAG_BOOLEAN;
  458. }
  459. bool isTrue() const {
  460. return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true));
  461. }
  462. bool isFalse() const {
  463. return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false));
  464. }
  465. bool isMagic() const {
  466. return toTag() == JSVAL_TAG_MAGIC;
  467. }
  468. bool isMagic(JSWhyMagic why) const {
  469. MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why);
  470. return isMagic();
  471. }
  472. bool isMarkable() const {
  473. return isGCThing() && !isNull();
  474. }
  475. JS::TraceKind traceKind() const {
  476. MOZ_ASSERT(isMarkable());
  477. static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
  478. "Value type tags must correspond with JS::TraceKinds.");
  479. static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
  480. "Value type tags must correspond with JS::TraceKinds.");
  481. static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
  482. "Value type tags must correspond with JS::TraceKinds.");
  483. if (MOZ_UNLIKELY(isPrivateGCThing()))
  484. return JS::GCThingTraceKind(toGCThing());
  485. return JS::TraceKind(toTag() & 0x03);
  486. }
  487. JSWhyMagic whyMagic() const {
  488. MOZ_ASSERT(isMagic());
  489. return data.s.payload.why;
  490. }
  491. uint32_t magicUint32() const {
  492. MOZ_ASSERT(isMagic());
  493. return data.s.payload.u32;
  494. }
  495. /*** Comparison ***/
  496. bool operator==(const Value& rhs) const {
  497. return data.asBits == rhs.data.asBits;
  498. }
  499. bool operator!=(const Value& rhs) const {
  500. return data.asBits != rhs.data.asBits;
  501. }
  502. friend inline bool SameType(const Value& lhs, const Value& rhs);
  503. /*** Extract the value's typed payload ***/
  504. int32_t toInt32() const {
  505. MOZ_ASSERT(isInt32());
  506. #if defined(JS_NUNBOX32)
  507. return data.s.payload.i32;
  508. #elif defined(JS_PUNBOX64)
  509. return int32_t(data.asBits);
  510. #endif
  511. }
  512. double toDouble() const {
  513. MOZ_ASSERT(isDouble());
  514. return data.asDouble;
  515. }
  516. double toNumber() const {
  517. MOZ_ASSERT(isNumber());
  518. return isDouble() ? toDouble() : double(toInt32());
  519. }
  520. JSString* toString() const {
  521. MOZ_ASSERT(isString());
  522. #if defined(JS_NUNBOX32)
  523. return data.s.payload.str;
  524. #elif defined(JS_PUNBOX64)
  525. return reinterpret_cast<JSString*>(data.asBits & JSVAL_PAYLOAD_MASK);
  526. #endif
  527. }
  528. JS::Symbol* toSymbol() const {
  529. MOZ_ASSERT(isSymbol());
  530. #if defined(JS_NUNBOX32)
  531. return data.s.payload.sym;
  532. #elif defined(JS_PUNBOX64)
  533. return reinterpret_cast<JS::Symbol*>(data.asBits & JSVAL_PAYLOAD_MASK);
  534. #endif
  535. }
  536. JSObject& toObject() const {
  537. MOZ_ASSERT(isObject());
  538. #if defined(JS_NUNBOX32)
  539. return *data.s.payload.obj;
  540. #elif defined(JS_PUNBOX64)
  541. return *toObjectOrNull();
  542. #endif
  543. }
  544. JSObject* toObjectOrNull() const {
  545. MOZ_ASSERT(isObjectOrNull());
  546. #if defined(JS_NUNBOX32)
  547. return data.s.payload.obj;
  548. #elif defined(JS_PUNBOX64)
  549. uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK;
  550. MOZ_ASSERT((ptrBits & 0x7) == 0);
  551. return reinterpret_cast<JSObject*>(ptrBits);
  552. #endif
  553. }
  554. js::gc::Cell* toGCThing() const {
  555. MOZ_ASSERT(isGCThing());
  556. #if defined(JS_NUNBOX32)
  557. return data.s.payload.cell;
  558. #elif defined(JS_PUNBOX64)
  559. uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK;
  560. MOZ_ASSERT((ptrBits & 0x7) == 0);
  561. return reinterpret_cast<js::gc::Cell*>(ptrBits);
  562. #endif
  563. }
  564. js::gc::Cell* toMarkablePointer() const {
  565. MOZ_ASSERT(isMarkable());
  566. return toGCThing();
  567. }
  568. GCCellPtr toGCCellPtr() const {
  569. return GCCellPtr(toGCThing(), traceKind());
  570. }
  571. bool toBoolean() const {
  572. MOZ_ASSERT(isBoolean());
  573. #if defined(JS_NUNBOX32)
  574. return bool(data.s.payload.boo);
  575. #elif defined(JS_PUNBOX64)
  576. return bool(data.asBits & JSVAL_PAYLOAD_MASK);
  577. #endif
  578. }
  579. uint32_t payloadAsRawUint32() const {
  580. MOZ_ASSERT(!isDouble());
  581. return data.s.payload.u32;
  582. }
  583. uint64_t asRawBits() const {
  584. return data.asBits;
  585. }
  586. JSValueType extractNonDoubleType() const {
  587. uint32_t type = toTag() & 0xF;
  588. MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
  589. return JSValueType(type);
  590. }
  591. /*
  592. * Private API
  593. *
  594. * Private setters/getters allow the caller to read/write arbitrary types
  595. * that fit in the 64-bit payload. It is the caller's responsibility, after
  596. * storing to a value with setPrivateX to read only using getPrivateX.
  597. * Privates values are given a type which ensures they are not marked.
  598. */
  599. void setPrivate(void* ptr) {
  600. MOZ_ASSERT((uintptr_t(ptr) & 1) == 0);
  601. #if defined(JS_NUNBOX32)
  602. data.s.tag = JSValueTag(0);
  603. data.s.payload.ptr = ptr;
  604. #elif defined(JS_PUNBOX64)
  605. data.asBits = uintptr_t(ptr) >> 1;
  606. #endif
  607. MOZ_ASSERT(isDouble());
  608. }
  609. void* toPrivate() const {
  610. MOZ_ASSERT(isDouble());
  611. #if defined(JS_NUNBOX32)
  612. return data.s.payload.ptr;
  613. #elif defined(JS_PUNBOX64)
  614. MOZ_ASSERT((data.asBits & 0x8000000000000000ULL) == 0);
  615. return reinterpret_cast<void*>(data.asBits << 1);
  616. #endif
  617. }
  618. void setPrivateUint32(uint32_t ui) {
  619. MOZ_ASSERT(uint32_t(int32_t(ui)) == ui);
  620. setInt32(int32_t(ui));
  621. }
  622. uint32_t toPrivateUint32() const {
  623. return uint32_t(toInt32());
  624. }
  625. /*
  626. * Private GC Thing API
  627. *
  628. * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit
  629. * payload as private GC things. Such Values are considered isMarkable()
  630. * and isGCThing(), and as such, automatically marked. Their traceKind()
  631. * is gotten via their cells.
  632. */
  633. void setPrivateGCThing(js::gc::Cell* cell) {
  634. MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
  635. "Private GC thing Values must not be strings. Make a StringValue instead.");
  636. MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
  637. "Private GC thing Values must not be symbols. Make a SymbolValue instead.");
  638. MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
  639. "Private GC thing Values must not be objects. Make an ObjectValue instead.");
  640. MOZ_ASSERT(uintptr_t(cell) > 0x1000);
  641. #if defined(JS_PUNBOX64)
  642. // VisualStudio cannot contain parenthesized C++ style cast and shift
  643. // inside decltype in template parameter:
  644. // AssertionConditionType<decltype((uintptr_t(x) >> 1))>
  645. // It throws syntax error.
  646. MOZ_ASSERT((((uintptr_t)cell) >> JSVAL_TAG_SHIFT) == 0);
  647. #endif
  648. data.asBits = bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING, PayloadType(cell));
  649. }
  650. bool isPrivateGCThing() const {
  651. return toTag() == JSVAL_TAG_PRIVATE_GCTHING;
  652. }
  653. const size_t* payloadWord() const {
  654. #if defined(JS_NUNBOX32)
  655. return &data.s.payload.word;
  656. #elif defined(JS_PUNBOX64)
  657. return &data.asWord;
  658. #endif
  659. }
  660. const uintptr_t* payloadUIntPtr() const {
  661. #if defined(JS_NUNBOX32)
  662. return &data.s.payload.uintptr;
  663. #elif defined(JS_PUNBOX64)
  664. return &data.asUIntPtr;
  665. #endif
  666. }
  667. #if !defined(_MSC_VER) && !defined(__sparc)
  668. // Value must be POD so that MSVC will pass it by value and not in memory
  669. // (bug 689101); the same is true for SPARC as well (bug 737344). More
  670. // precisely, we don't want Value return values compiled as out params.
  671. private:
  672. #endif
  673. #if MOZ_LITTLE_ENDIAN
  674. # if defined(JS_NUNBOX32)
  675. union layout {
  676. uint64_t asBits;
  677. struct {
  678. union {
  679. int32_t i32;
  680. uint32_t u32;
  681. uint32_t boo; // Don't use |bool| -- it must be four bytes.
  682. JSString* str;
  683. JS::Symbol* sym;
  684. JSObject* obj;
  685. js::gc::Cell* cell;
  686. void* ptr;
  687. JSWhyMagic why;
  688. size_t word;
  689. uintptr_t uintptr;
  690. } payload;
  691. JSValueTag tag;
  692. } s;
  693. double asDouble;
  694. void* asPtr;
  695. layout() = default;
  696. explicit constexpr layout(uint64_t bits) : asBits(bits) {}
  697. explicit constexpr layout(double d) : asDouble(d) {}
  698. } data;
  699. # elif defined(JS_PUNBOX64)
  700. union layout {
  701. uint64_t asBits;
  702. #if !defined(_WIN64)
  703. /* MSVC does not pack these correctly :-( */
  704. struct {
  705. uint64_t payload47 : 47;
  706. JSValueTag tag : 17;
  707. } debugView;
  708. #endif
  709. struct {
  710. union {
  711. int32_t i32;
  712. uint32_t u32;
  713. JSWhyMagic why;
  714. } payload;
  715. } s;
  716. double asDouble;
  717. void* asPtr;
  718. size_t asWord;
  719. uintptr_t asUIntPtr;
  720. layout() = default;
  721. explicit constexpr layout(uint64_t bits) : asBits(bits) {}
  722. explicit constexpr layout(double d) : asDouble(d) {}
  723. } data;
  724. # endif /* JS_PUNBOX64 */
  725. #else /* MOZ_LITTLE_ENDIAN */
  726. # if defined(JS_NUNBOX32)
  727. union layout {
  728. uint64_t asBits;
  729. struct {
  730. JSValueTag tag;
  731. union {
  732. int32_t i32;
  733. uint32_t u32;
  734. uint32_t boo; // Don't use |bool| -- it must be four bytes.
  735. JSString* str;
  736. JS::Symbol* sym;
  737. JSObject* obj;
  738. js::gc::Cell* cell;
  739. void* ptr;
  740. JSWhyMagic why;
  741. size_t word;
  742. uintptr_t uintptr;
  743. } payload;
  744. } s;
  745. double asDouble;
  746. void* asPtr;
  747. layout() = default;
  748. explicit constexpr layout(uint64_t bits) : asBits(bits) {}
  749. explicit constexpr layout(double d) : asDouble(d) {}
  750. } data;
  751. # elif defined(JS_PUNBOX64)
  752. union layout {
  753. uint64_t asBits;
  754. struct {
  755. JSValueTag tag : 17;
  756. uint64_t payload47 : 47;
  757. } debugView;
  758. struct {
  759. uint32_t padding;
  760. union {
  761. int32_t i32;
  762. uint32_t u32;
  763. JSWhyMagic why;
  764. } payload;
  765. } s;
  766. double asDouble;
  767. void* asPtr;
  768. size_t asWord;
  769. uintptr_t asUIntPtr;
  770. layout() = default;
  771. explicit constexpr layout(uint64_t bits) : asBits(bits) {}
  772. explicit constexpr layout(double d) : asDouble(d) {}
  773. } data;
  774. # endif /* JS_PUNBOX64 */
  775. #endif /* MOZ_LITTLE_ENDIAN */
  776. private:
  777. explicit constexpr Value(uint64_t asBits) : data(asBits) {}
  778. explicit constexpr Value(double d) : data(d) {}
  779. void staticAssertions() {
  780. JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
  781. JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
  782. JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4);
  783. JS_STATIC_ASSERT(sizeof(Value) == 8);
  784. }
  785. friend constexpr Value JS::UndefinedValue();
  786. public:
  787. static constexpr uint64_t
  788. bitsFromTagAndPayload(JSValueTag tag, PayloadType payload)
  789. {
  790. #if defined(JS_NUNBOX32)
  791. return (uint64_t(uint32_t(tag)) << 32) | payload;
  792. #elif defined(JS_PUNBOX64)
  793. return (uint64_t(uint32_t(tag)) << JSVAL_TAG_SHIFT) | payload;
  794. #endif
  795. }
  796. static constexpr Value
  797. fromTagAndPayload(JSValueTag tag, PayloadType payload)
  798. {
  799. return fromRawBits(bitsFromTagAndPayload(tag, payload));
  800. }
  801. static constexpr Value
  802. fromRawBits(uint64_t asBits) {
  803. return Value(asBits);
  804. }
  805. static constexpr Value
  806. fromInt32(int32_t i) {
  807. return fromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
  808. }
  809. static constexpr Value
  810. fromDouble(double d) {
  811. return Value(d);
  812. }
  813. } JS_HAZ_GC_POINTER;
  814. static_assert(sizeof(Value) == 8, "Value size must leave three tag bits, be a binary power, and is ubiquitously depended upon everywhere");
  815. inline bool
  816. IsOptimizedPlaceholderMagicValue(const Value& v)
  817. {
  818. if (v.isMagic()) {
  819. MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT);
  820. return true;
  821. }
  822. return false;
  823. }
  824. static MOZ_ALWAYS_INLINE void
  825. ExposeValueToActiveJS(const Value& v)
  826. {
  827. if (v.isMarkable())
  828. js::gc::ExposeGCThingToActiveJS(GCCellPtr(v));
  829. }
  830. /************************************************************************/
  831. static inline Value
  832. NullValue()
  833. {
  834. Value v;
  835. v.setNull();
  836. return v;
  837. }
  838. static inline constexpr Value
  839. UndefinedValue()
  840. {
  841. return Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
  842. }
  843. static inline constexpr Value
  844. Int32Value(int32_t i32)
  845. {
  846. return Value::fromInt32(i32);
  847. }
  848. static inline Value
  849. DoubleValue(double dbl)
  850. {
  851. Value v;
  852. v.setDouble(dbl);
  853. return v;
  854. }
  855. static inline Value
  856. CanonicalizedDoubleValue(double d)
  857. {
  858. return MOZ_UNLIKELY(mozilla::IsNaN(d))
  859. ? Value::fromRawBits(detail::CanonicalizedNaNBits)
  860. : Value::fromDouble(d);
  861. }
  862. static inline bool
  863. IsCanonicalized(double d)
  864. {
  865. if (mozilla::IsInfinite(d) || mozilla::IsFinite(d))
  866. return true;
  867. uint64_t bits;
  868. mozilla::BitwiseCast<uint64_t>(d, &bits);
  869. return (bits & ~mozilla::DoubleTypeTraits::kSignBit) == detail::CanonicalizedNaNBits;
  870. }
  871. static inline Value
  872. DoubleNaNValue()
  873. {
  874. Value v;
  875. v.setNaN();
  876. return v;
  877. }
  878. static inline Value
  879. Float32Value(float f)
  880. {
  881. Value v;
  882. v.setDouble(f);
  883. return v;
  884. }
  885. static inline Value
  886. StringValue(JSString* str)
  887. {
  888. Value v;
  889. v.setString(str);
  890. return v;
  891. }
  892. static inline Value
  893. SymbolValue(JS::Symbol* sym)
  894. {
  895. Value v;
  896. v.setSymbol(sym);
  897. return v;
  898. }
  899. static inline Value
  900. BooleanValue(bool boo)
  901. {
  902. Value v;
  903. v.setBoolean(boo);
  904. return v;
  905. }
  906. static inline Value
  907. TrueValue()
  908. {
  909. Value v;
  910. v.setBoolean(true);
  911. return v;
  912. }
  913. static inline Value
  914. FalseValue()
  915. {
  916. Value v;
  917. v.setBoolean(false);
  918. return v;
  919. }
  920. static inline Value
  921. ObjectValue(JSObject& obj)
  922. {
  923. Value v;
  924. v.setObject(obj);
  925. return v;
  926. }
  927. static inline Value
  928. ObjectValueCrashOnTouch()
  929. {
  930. Value v;
  931. v.setObject(*reinterpret_cast<JSObject*>(0x48));
  932. return v;
  933. }
  934. static inline Value
  935. MagicValue(JSWhyMagic why)
  936. {
  937. Value v;
  938. v.setMagic(why);
  939. return v;
  940. }
  941. static inline Value
  942. MagicValueUint32(uint32_t payload)
  943. {
  944. Value v;
  945. v.setMagicUint32(payload);
  946. return v;
  947. }
  948. static inline Value
  949. NumberValue(float f)
  950. {
  951. Value v;
  952. v.setNumber(f);
  953. return v;
  954. }
  955. static inline Value
  956. NumberValue(double dbl)
  957. {
  958. Value v;
  959. v.setNumber(dbl);
  960. return v;
  961. }
  962. static inline Value
  963. NumberValue(int8_t i)
  964. {
  965. return Int32Value(i);
  966. }
  967. static inline Value
  968. NumberValue(uint8_t i)
  969. {
  970. return Int32Value(i);
  971. }
  972. static inline Value
  973. NumberValue(int16_t i)
  974. {
  975. return Int32Value(i);
  976. }
  977. static inline Value
  978. NumberValue(uint16_t i)
  979. {
  980. return Int32Value(i);
  981. }
  982. static inline Value
  983. NumberValue(int32_t i)
  984. {
  985. return Int32Value(i);
  986. }
  987. static inline constexpr Value
  988. NumberValue(uint32_t i)
  989. {
  990. return i <= JSVAL_INT_MAX
  991. ? Int32Value(int32_t(i))
  992. : Value::fromDouble(double(i));
  993. }
  994. namespace detail {
  995. template <bool Signed>
  996. class MakeNumberValue
  997. {
  998. public:
  999. template<typename T>
  1000. static inline Value create(const T t)
  1001. {
  1002. Value v;
  1003. if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX)
  1004. v.setInt32(int32_t(t));
  1005. else
  1006. v.setDouble(double(t));
  1007. return v;
  1008. }
  1009. };
  1010. template <>
  1011. class MakeNumberValue<false>
  1012. {
  1013. public:
  1014. template<typename T>
  1015. static inline Value create(const T t)
  1016. {
  1017. Value v;
  1018. if (t <= JSVAL_INT_MAX)
  1019. v.setInt32(int32_t(t));
  1020. else
  1021. v.setDouble(double(t));
  1022. return v;
  1023. }
  1024. };
  1025. } // namespace detail
  1026. template <typename T>
  1027. static inline Value
  1028. NumberValue(const T t)
  1029. {
  1030. MOZ_ASSERT(Value::isNumberRepresentable(t), "value creation would be lossy");
  1031. return detail::MakeNumberValue<std::numeric_limits<T>::is_signed>::create(t);
  1032. }
  1033. static inline Value
  1034. ObjectOrNullValue(JSObject* obj)
  1035. {
  1036. Value v;
  1037. v.setObjectOrNull(obj);
  1038. return v;
  1039. }
  1040. static inline Value
  1041. PrivateValue(void* ptr)
  1042. {
  1043. Value v;
  1044. v.setPrivate(ptr);
  1045. return v;
  1046. }
  1047. static inline Value
  1048. PrivateUint32Value(uint32_t ui)
  1049. {
  1050. Value v;
  1051. v.setPrivateUint32(ui);
  1052. return v;
  1053. }
  1054. static inline Value
  1055. PrivateGCThingValue(js::gc::Cell* cell)
  1056. {
  1057. Value v;
  1058. v.setPrivateGCThing(cell);
  1059. return v;
  1060. }
  1061. static inline Value
  1062. PoisonedObjectValue(JSObject* obj)
  1063. {
  1064. Value v;
  1065. v.setObjectNoCheck(obj);
  1066. return v;
  1067. }
  1068. inline bool
  1069. SameType(const Value& lhs, const Value& rhs)
  1070. {
  1071. #if defined(JS_NUNBOX32)
  1072. JSValueTag ltag = lhs.toTag(), rtag = rhs.toTag();
  1073. return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
  1074. #elif defined(JS_PUNBOX64)
  1075. return (lhs.isDouble() && rhs.isDouble()) ||
  1076. (((lhs.data.asBits ^ rhs.data.asBits) & 0xFFFF800000000000ULL) == 0);
  1077. #endif
  1078. }
  1079. } // namespace JS
  1080. /************************************************************************/
  1081. namespace JS {
  1082. JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const Value& next);
  1083. template <>
  1084. struct GCPolicy<JS::Value>
  1085. {
  1086. static Value initial() { return UndefinedValue(); }
  1087. static void trace(JSTracer* trc, Value* v, const char* name) {
  1088. js::UnsafeTraceManuallyBarrieredEdge(trc, v, name);
  1089. }
  1090. static bool isTenured(const Value& thing) {
  1091. return !thing.isGCThing() || !IsInsideNursery(thing.toGCThing());
  1092. }
  1093. };
  1094. } // namespace JS
  1095. namespace js {
  1096. template <>
  1097. struct BarrierMethods<JS::Value>
  1098. {
  1099. static gc::Cell* asGCThingOrNull(const JS::Value& v) {
  1100. return v.isMarkable() ? v.toGCThing() : nullptr;
  1101. }
  1102. static void postBarrier(JS::Value* v, const JS::Value& prev, const JS::Value& next) {
  1103. JS::HeapValuePostBarrier(v, prev, next);
  1104. }
  1105. static void exposeToJS(const JS::Value& v) {
  1106. JS::ExposeValueToActiveJS(v);
  1107. }
  1108. };
  1109. template <class Outer> class MutableValueOperations;
  1110. /**
  1111. * A class designed for CRTP use in implementing the non-mutating parts of the
  1112. * Value interface in Value-like classes. Outer must be a class inheriting
  1113. * ValueOperations<Outer> with a visible get() method returning a const
  1114. * reference to the Value abstracted by Outer.
  1115. */
  1116. template <class Outer>
  1117. class ValueOperations
  1118. {
  1119. friend class MutableValueOperations<Outer>;
  1120. const JS::Value& value() const { return static_cast<const Outer*>(this)->get(); }
  1121. public:
  1122. bool isUndefined() const { return value().isUndefined(); }
  1123. bool isNull() const { return value().isNull(); }
  1124. bool isBoolean() const { return value().isBoolean(); }
  1125. bool isTrue() const { return value().isTrue(); }
  1126. bool isFalse() const { return value().isFalse(); }
  1127. bool isNumber() const { return value().isNumber(); }
  1128. bool isInt32() const { return value().isInt32(); }
  1129. bool isInt32(int32_t i32) const { return value().isInt32(i32); }
  1130. bool isDouble() const { return value().isDouble(); }
  1131. bool isString() const { return value().isString(); }
  1132. bool isSymbol() const { return value().isSymbol(); }
  1133. bool isObject() const { return value().isObject(); }
  1134. bool isMagic() const { return value().isMagic(); }
  1135. bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
  1136. bool isMarkable() const { return value().isMarkable(); }
  1137. bool isPrimitive() const { return value().isPrimitive(); }
  1138. bool isGCThing() const { return value().isGCThing(); }
  1139. bool isNullOrUndefined() const { return value().isNullOrUndefined(); }
  1140. bool isObjectOrNull() const { return value().isObjectOrNull(); }
  1141. bool toBoolean() const { return value().toBoolean(); }
  1142. double toNumber() const { return value().toNumber(); }
  1143. int32_t toInt32() const { return value().toInt32(); }
  1144. double toDouble() const { return value().toDouble(); }
  1145. JSString* toString() const { return value().toString(); }
  1146. JS::Symbol* toSymbol() const { return value().toSymbol(); }
  1147. JSObject& toObject() const { return value().toObject(); }
  1148. JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
  1149. gc::Cell* toGCThing() const { return value().toGCThing(); }
  1150. JS::TraceKind traceKind() const { return value().traceKind(); }
  1151. void* toPrivate() const { return value().toPrivate(); }
  1152. uint32_t toPrivateUint32() const { return value().toPrivateUint32(); }
  1153. uint64_t asRawBits() const { return value().asRawBits(); }
  1154. JSValueType extractNonDoubleType() const { return value().extractNonDoubleType(); }
  1155. JSWhyMagic whyMagic() const { return value().whyMagic(); }
  1156. uint32_t magicUint32() const { return value().magicUint32(); }
  1157. };
  1158. /**
  1159. * A class designed for CRTP use in implementing all the mutating parts of the
  1160. * Value interface in Value-like classes. Outer must be a class inheriting
  1161. * MutableValueOperations<Outer> with visible get() methods returning const and
  1162. * non-const references to the Value abstracted by Outer.
  1163. */
  1164. template <class Outer>
  1165. class MutableValueOperations : public ValueOperations<Outer>
  1166. {
  1167. JS::Value& value() { return static_cast<Outer*>(this)->get(); }
  1168. public:
  1169. void setNull() { value().setNull(); }
  1170. void setUndefined() { value().setUndefined(); }
  1171. void setInt32(int32_t i) { value().setInt32(i); }
  1172. void setDouble(double d) { value().setDouble(d); }
  1173. void setNaN() { setDouble(JS::GenericNaN()); }
  1174. void setBoolean(bool b) { value().setBoolean(b); }
  1175. void setMagic(JSWhyMagic why) { value().setMagic(why); }
  1176. bool setNumber(uint32_t ui) { return value().setNumber(ui); }
  1177. bool setNumber(double d) { return value().setNumber(d); }
  1178. void setString(JSString* str) { this->value().setString(str); }
  1179. void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); }
  1180. void setObject(JSObject& obj) { this->value().setObject(obj); }
  1181. void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); }
  1182. void setPrivate(void* ptr) { this->value().setPrivate(ptr); }
  1183. void setPrivateUint32(uint32_t ui) { this->value().setPrivateUint32(ui); }
  1184. void setPrivateGCThing(js::gc::Cell* cell) { this->value().setPrivateGCThing(cell); }
  1185. };
  1186. /*
  1187. * Augment the generic Heap<T> interface when T = Value with
  1188. * type-querying, value-extracting, and mutating operations.
  1189. */
  1190. template <>
  1191. class HeapBase<JS::Value> : public ValueOperations<JS::Heap<JS::Value> >
  1192. {
  1193. typedef JS::Heap<JS::Value> Outer;
  1194. friend class ValueOperations<Outer>;
  1195. void setBarriered(const JS::Value& v) {
  1196. *static_cast<JS::Heap<JS::Value>*>(this) = v;
  1197. }
  1198. public:
  1199. void setNull() { setBarriered(JS::NullValue()); }
  1200. void setUndefined() { setBarriered(JS::UndefinedValue()); }
  1201. void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); }
  1202. void setDouble(double d) { setBarriered(JS::DoubleValue(d)); }
  1203. void setNaN() { setDouble(JS::GenericNaN()); }
  1204. void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); }
  1205. void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); }
  1206. void setString(JSString* str) { setBarriered(JS::StringValue(str)); }
  1207. void setSymbol(JS::Symbol* sym) { setBarriered(JS::SymbolValue(sym)); }
  1208. void setObject(JSObject& obj) { setBarriered(JS::ObjectValue(obj)); }
  1209. void setPrivateGCThing(js::gc::Cell* cell) { setBarriered(JS::PrivateGCThingValue(cell)); }
  1210. bool setNumber(uint32_t ui) {
  1211. if (ui > JSVAL_INT_MAX) {
  1212. setDouble((double)ui);
  1213. return false;
  1214. } else {
  1215. setInt32((int32_t)ui);
  1216. return true;
  1217. }
  1218. }
  1219. bool setNumber(double d) {
  1220. int32_t i;
  1221. if (mozilla::NumberIsInt32(d, &i)) {
  1222. setInt32(i);
  1223. return true;
  1224. }
  1225. setDouble(d);
  1226. return false;
  1227. }
  1228. void setObjectOrNull(JSObject* arg) {
  1229. if (arg)
  1230. setObject(*arg);
  1231. else
  1232. setNull();
  1233. }
  1234. };
  1235. template <>
  1236. class HandleBase<JS::Value> : public ValueOperations<JS::Handle<JS::Value> >
  1237. {};
  1238. template <>
  1239. class MutableHandleBase<JS::Value> : public MutableValueOperations<JS::MutableHandle<JS::Value> >
  1240. {};
  1241. template <>
  1242. class RootedBase<JS::Value> : public MutableValueOperations<JS::Rooted<JS::Value> >
  1243. {};
  1244. template <>
  1245. class PersistentRootedBase<JS::Value> : public MutableValueOperations<JS::PersistentRooted<JS::Value>>
  1246. {};
  1247. /*
  1248. * If the Value is a GC pointer type, convert to that type and call |f| with
  1249. * the pointer. If the Value is not a GC type, calls F::defaultValue.
  1250. */
  1251. template <typename F, typename... Args>
  1252. auto
  1253. DispatchTyped(F f, const JS::Value& val, Args&&... args)
  1254. -> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
  1255. {
  1256. if (val.isString())
  1257. return f(val.toString(), mozilla::Forward<Args>(args)...);
  1258. if (val.isObject())
  1259. return f(&val.toObject(), mozilla::Forward<Args>(args)...);
  1260. if (val.isSymbol())
  1261. return f(val.toSymbol(), mozilla::Forward<Args>(args)...);
  1262. if (MOZ_UNLIKELY(val.isPrivateGCThing()))
  1263. return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward<Args>(args)...);
  1264. MOZ_ASSERT(!val.isMarkable());
  1265. return F::defaultValue(val);
  1266. }
  1267. template <class S> struct VoidDefaultAdaptor { static void defaultValue(const S&) {} };
  1268. template <class S> struct IdentityDefaultAdaptor { static S defaultValue(const S& v) {return v;} };
  1269. template <class S, bool v> struct BoolDefaultAdaptor { static bool defaultValue(const S&) { return v; } };
  1270. } // namespace js
  1271. /************************************************************************/
  1272. namespace JS {
  1273. extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue;
  1274. extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue;
  1275. extern JS_PUBLIC_DATA(const HandleValue) TrueHandleValue;
  1276. extern JS_PUBLIC_DATA(const HandleValue) FalseHandleValue;
  1277. } // namespace JS
  1278. #endif /* js_Value_h */