Value.h 43 KB

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