123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- /* JS::Value implementation. */
- #ifndef js_Value_h
- #define js_Value_h
- #include "mozilla/Attributes.h"
- #include "mozilla/Casting.h"
- #include "mozilla/FloatingPoint.h"
- #include "mozilla/Likely.h"
- #include <limits> /* for std::numeric_limits */
- #include "js-config.h"
- #include "jstypes.h"
- #include "js/GCAPI.h"
- #include "js/RootingAPI.h"
- #include "js/Utility.h"
- namespace JS { class Value; }
- /* JS::Value can store a full int32_t. */
- #define JSVAL_INT_BITS 32
- #define JSVAL_INT_MIN ((int32_t)0x80000000)
- #define JSVAL_INT_MAX ((int32_t)0x7fffffff)
- #if defined(JS_PUNBOX64)
- # define JSVAL_TAG_SHIFT 47
- #endif
- // Use enums so that printing a JS::Value in the debugger shows nice
- // symbolic type tags.
- #if defined(_MSC_VER)
- # define JS_ENUM_HEADER(id, type) enum id : type
- # define JS_ENUM_FOOTER(id)
- #else
- # define JS_ENUM_HEADER(id, type) enum id
- # define JS_ENUM_FOOTER(id) __attribute__((packed))
- #endif
- /* Remember to propagate changes to the C defines below. */
- JS_ENUM_HEADER(JSValueType, uint8_t)
- {
- JSVAL_TYPE_DOUBLE = 0x00,
- JSVAL_TYPE_INT32 = 0x01,
- JSVAL_TYPE_UNDEFINED = 0x02,
- JSVAL_TYPE_NULL = 0x03,
- JSVAL_TYPE_BOOLEAN = 0x04,
- JSVAL_TYPE_MAGIC = 0x05,
- JSVAL_TYPE_STRING = 0x06,
- JSVAL_TYPE_SYMBOL = 0x07,
- JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
- JSVAL_TYPE_OBJECT = 0x0c,
- /* These never appear in a jsval; they are only provided as an out-of-band value. */
- JSVAL_TYPE_UNKNOWN = 0x20,
- JSVAL_TYPE_MISSING = 0x21
- } JS_ENUM_FOOTER(JSValueType);
- static_assert(sizeof(JSValueType) == 1,
- "compiler typed enum support is apparently buggy");
- #if defined(JS_NUNBOX32)
- /* Remember to propagate changes to the C defines below. */
- JS_ENUM_HEADER(JSValueTag, uint32_t)
- {
- JSVAL_TAG_CLEAR = 0xFFFFFF80,
- JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
- JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
- JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
- JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
- JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
- JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
- JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
- JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT,
- JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING
- } JS_ENUM_FOOTER(JSValueTag);
- static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
- "compiler typed enum support is apparently buggy");
- #elif defined(JS_PUNBOX64)
- /* Remember to propagate changes to the C defines below. */
- JS_ENUM_HEADER(JSValueTag, uint32_t)
- {
- JSVAL_TAG_MAX_DOUBLE = 0x1FFF0,
- JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
- JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
- JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
- JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
- JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
- JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
- JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
- JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT,
- JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING
- } JS_ENUM_FOOTER(JSValueTag);
- static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
- "compiler typed enum support is apparently buggy");
- JS_ENUM_HEADER(JSValueShiftedTag, uint64_t)
- {
- JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
- JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT),
- JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT),
- JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT),
- JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT),
- JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT),
- JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT),
- JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT),
- JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT),
- JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT)
- } JS_ENUM_FOOTER(JSValueShiftedTag);
- static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
- "compiler typed enum support is apparently buggy");
- #endif
- /*
- * All our supported compilers implement C++11 |enum Foo : T| syntax, so don't
- * expose these macros. (This macro exists *only* because gcc bug 51242
- * <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51242> makes bit-fields of
- * typed enums trigger a warning that can't be turned off. Don't expose it
- * beyond this file!)
- */
- #undef JS_ENUM_HEADER
- #undef JS_ENUM_FOOTER
- #if defined(JS_NUNBOX32)
- #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type)))
- #define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << 32)
- #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT
- #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32
- #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING
- #elif defined(JS_PUNBOX64)
- #define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT)
- #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL
- #define JSVAL_TAG_MASK 0xFFFF800000000000LL
- #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type)))
- #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT)
- #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT
- #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32
- #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING
- #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT
- #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED
- #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING
- #endif /* JS_PUNBOX64 */
- typedef enum JSWhyMagic
- {
- /** a hole in a native object's elements */
- JS_ELEMENTS_HOLE,
- /** there is not a pending iterator value */
- JS_NO_ITER_VALUE,
- /** exception value thrown when closing a generator */
- JS_GENERATOR_CLOSING,
- /** compiler sentinel value */
- JS_NO_CONSTANT,
- /** used in debug builds to catch tracing errors */
- JS_THIS_POISON,
- /** used in debug builds to catch tracing errors */
- JS_ARG_POISON,
- /** an empty subnode in the AST serializer */
- JS_SERIALIZE_NO_NODE,
- /** lazy arguments value on the stack */
- JS_LAZY_ARGUMENTS,
- /** optimized-away 'arguments' value */
- JS_OPTIMIZED_ARGUMENTS,
- /** magic value passed to natives to indicate construction */
- JS_IS_CONSTRUCTING,
- /** value of static block object slot */
- JS_BLOCK_NEEDS_CLONE,
- /** see class js::HashableValue */
- JS_HASH_KEY_EMPTY,
- /** error while running Ion code */
- JS_ION_ERROR,
- /** missing recover instruction result */
- JS_ION_BAILOUT,
- /** optimized out slot */
- JS_OPTIMIZED_OUT,
- /** uninitialized lexical bindings that produce ReferenceError on touch. */
- JS_UNINITIALIZED_LEXICAL,
- /** for local use */
- JS_GENERIC_MAGIC,
- JS_WHY_MAGIC_COUNT
- } JSWhyMagic;
- namespace JS {
- static inline constexpr JS::Value UndefinedValue();
- static inline JS::Value PoisonedObjectValue(JSObject* obj);
- namespace detail {
- constexpr int CanonicalizedNaNSignBit = 0;
- #if defined(__mips__) && !defined(__mips_nan2008)
- constexpr uint64_t CanonicalizedNaNSignificand = 0x7FFFFFFFFFFFFULL;
- #else
- constexpr uint64_t CanonicalizedNaNSignificand = 0x8000000000000ULL;
- #endif
- constexpr uint64_t CanonicalizedNaNBits =
- mozilla::SpecificNaNBits<double,
- detail::CanonicalizedNaNSignBit,
- detail::CanonicalizedNaNSignificand>::value;
- } // namespace detail
- /**
- * Returns a generic quiet NaN value, with all payload bits set to zero.
- *
- * Among other properties, this NaN's bit pattern conforms to JS::Value's
- * bit pattern restrictions.
- */
- static MOZ_ALWAYS_INLINE double
- GenericNaN()
- {
- return mozilla::SpecificNaN<double>(detail::CanonicalizedNaNSignBit,
- detail::CanonicalizedNaNSignificand);
- }
- /* MSVC with PGO miscompiles this function. */
- #if defined(_MSC_VER)
- # pragma optimize("g", off)
- #endif
- static inline double
- CanonicalizeNaN(double d)
- {
- if (MOZ_UNLIKELY(mozilla::IsNaN(d)))
- return GenericNaN();
- return d;
- }
- #if defined(_MSC_VER)
- # pragma optimize("", on)
- #endif
- /**
- * JS::Value is the interface for a single JavaScript Engine value. A few
- * general notes on JS::Value:
- *
- * - JS::Value has setX() and isX() members for X in
- *
- * { Int32, Double, String, Symbol, Boolean, Undefined, Null, Object, Magic }
- *
- * JS::Value also contains toX() for each of the non-singleton types.
- *
- * - Magic is a singleton type whose payload contains either a JSWhyMagic "reason" for
- * the magic value or a uint32_t value. By providing JSWhyMagic values when
- * creating and checking for magic values, it is possible to assert, at
- * runtime, that only magic values with the expected reason flow through a
- * particular value. For example, if cx->exception has a magic value, the
- * reason must be JS_GENERATOR_CLOSING.
- *
- * - The JS::Value operations are preferred. The JSVAL_* operations remain for
- * compatibility; they may be removed at some point. These operations mostly
- * provide similar functionality. But there are a few key differences. One
- * is that JS::Value gives null a separate type.
- * Also, to help prevent mistakenly boxing a nullable JSObject* as an object,
- * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a
- * JSObject&.) A convenience member Value::setObjectOrNull is provided.
- *
- * - JSVAL_VOID is the same as the singleton value of the Undefined type.
- *
- * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on
- * 32-bit user code should avoid copying jsval/JS::Value as much as possible,
- * preferring to pass by const Value&.
- */
- class MOZ_NON_PARAM alignas(8) Value
- {
- public:
- #if defined(JS_NUNBOX32)
- using PayloadType = uint32_t;
- #elif defined(JS_PUNBOX64)
- using PayloadType = uint64_t;
- #endif
- /*
- * N.B. the default constructor leaves Value unitialized. Adding a default
- * constructor prevents Value from being stored in a union.
- */
- Value() = default;
- Value(const Value& v) = default;
- /**
- * Returns false if creating a NumberValue containing the given type would
- * be lossy, true otherwise.
- */
- template <typename T>
- static bool isNumberRepresentable(const T t) {
- return T(double(t)) == t;
- }
- /*** Mutators ***/
- void setNull() {
- data.asBits = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0);
- }
- void setUndefined() {
- data.asBits = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
- }
- void setInt32(int32_t i) {
- data.asBits = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
- }
- int32_t& getInt32Ref() {
- MOZ_ASSERT(isInt32());
- return data.s.payload.i32;
- }
- void setDouble(double d) {
- // Don't assign to data.asDouble to fix a miscompilation with
- // GCC 5.2.1 and 5.3.1. See bug 1312488.
- data = layout(d);
- MOZ_ASSERT(isDouble());
- }
- void setNaN() {
- setDouble(GenericNaN());
- }
- double& getDoubleRef() {
- MOZ_ASSERT(isDouble());
- return data.asDouble;
- }
- void setString(JSString* str) {
- MOZ_ASSERT(uintptr_t(str) > 0x1000);
- data.asBits = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str));
- }
- void setSymbol(JS::Symbol* sym) {
- MOZ_ASSERT(uintptr_t(sym) > 0x1000);
- data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym));
- }
- void setObject(JSObject& obj) {
- MOZ_ASSERT(uintptr_t(&obj) > 0x1000 || uintptr_t(&obj) == 0x48);
- #if defined(JS_PUNBOX64)
- // VisualStudio cannot contain parenthesized C++ style cast and shift
- // inside decltype in template parameter:
- // AssertionConditionType<decltype((uintptr_t(x) >> 1))>
- // It throws syntax error.
- MOZ_ASSERT((((uintptr_t)&obj) >> JSVAL_TAG_SHIFT) == 0);
- #endif
- setObjectNoCheck(&obj);
- }
- private:
- void setObjectNoCheck(JSObject* obj) {
- data.asBits = bitsFromTagAndPayload(JSVAL_TAG_OBJECT, PayloadType(obj));
- }
- friend inline Value PoisonedObjectValue(JSObject* obj);
- public:
- void setBoolean(bool b) {
- data.asBits = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b));
- }
- void setMagic(JSWhyMagic why) {
- data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why));
- }
- void setMagicUint32(uint32_t payload) {
- data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload);
- }
- void setNumber(uint32_t ui) {
- if (ui > JSVAL_INT_MAX) {
- setDouble((double)ui);
- } else {
- setInt32((int32_t)ui);
- }
- }
- void setNumber(double d) {
- int32_t i;
- if (mozilla::NumberIsInt32(d, &i)) {
- setInt32(i);
- } else {
- setDouble(d);
- }
- }
- void setObjectOrNull(JSObject* arg) {
- if (arg)
- setObject(*arg);
- else
- setNull();
- }
- void swap(Value& rhs) {
- uint64_t tmp = rhs.data.asBits;
- rhs.data.asBits = data.asBits;
- data.asBits = tmp;
- }
- private:
- JSValueTag toTag() const {
- #if defined(JS_NUNBOX32)
- return data.s.tag;
- #elif defined(JS_PUNBOX64)
- return JSValueTag(data.asBits >> JSVAL_TAG_SHIFT);
- #endif
- }
- public:
- /*** JIT-only interfaces to interact with and create raw Values ***/
- #if defined(JS_NUNBOX32)
- PayloadType toNunboxPayload() const {
- return data.s.payload.i32;
- }
- JSValueTag toNunboxTag() const {
- return data.s.tag;
- }
- #elif defined(JS_PUNBOX64)
- const void* bitsAsPunboxPointer() const {
- return reinterpret_cast<void*>(data.asBits);
- }
- #endif
- /*** Value type queries ***/
- /*
- * N.B. GCC, in some but not all cases, chooses to emit signed comparison
- * of JSValueTag even though its underlying type has been forced to be
- * uint32_t. Thus, all comparisons should explicitly cast operands to
- * uint32_t.
- */
- bool isUndefined() const {
- #if defined(JS_NUNBOX32)
- return toTag() == JSVAL_TAG_UNDEFINED;
- #elif defined(JS_PUNBOX64)
- return data.asBits == JSVAL_SHIFTED_TAG_UNDEFINED;
- #endif
- }
- bool isNull() const {
- #if defined(JS_NUNBOX32)
- return toTag() == JSVAL_TAG_NULL;
- #elif defined(JS_PUNBOX64)
- return data.asBits == JSVAL_SHIFTED_TAG_NULL;
- #endif
- }
- bool isNullOrUndefined() const {
- return isNull() || isUndefined();
- }
- bool isInt32() const {
- return toTag() == JSVAL_TAG_INT32;
- }
- bool isInt32(int32_t i32) const {
- return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32));
- }
- bool isDouble() const {
- #if defined(JS_NUNBOX32)
- return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR);
- #elif defined(JS_PUNBOX64)
- return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
- #endif
- }
- bool isNumber() const {
- #if defined(JS_NUNBOX32)
- MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR);
- return uint32_t(toTag()) <= uint32_t(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET);
- #elif defined(JS_PUNBOX64)
- return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET;
- #endif
- }
- bool isString() const {
- return toTag() == JSVAL_TAG_STRING;
- }
- bool isSymbol() const {
- return toTag() == JSVAL_TAG_SYMBOL;
- }
- bool isObject() const {
- #if defined(JS_NUNBOX32)
- return toTag() == JSVAL_TAG_OBJECT;
- #elif defined(JS_PUNBOX64)
- MOZ_ASSERT((data.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
- return data.asBits >= JSVAL_SHIFTED_TAG_OBJECT;
- #endif
- }
- bool isPrimitive() const {
- #if defined(JS_NUNBOX32)
- return uint32_t(toTag()) < uint32_t(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET);
- #elif defined(JS_PUNBOX64)
- return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET;
- #endif
- }
- bool isObjectOrNull() const {
- return isObject() || isNull();
- }
- bool isGCThing() const {
- #if defined(JS_NUNBOX32)
- /* gcc sometimes generates signed < without explicit casts. */
- return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET);
- #elif defined(JS_PUNBOX64)
- return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET;
- #endif
- }
- bool isBoolean() const {
- return toTag() == JSVAL_TAG_BOOLEAN;
- }
- bool isTrue() const {
- return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true));
- }
- bool isFalse() const {
- return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false));
- }
- bool isMagic() const {
- return toTag() == JSVAL_TAG_MAGIC;
- }
- bool isMagic(JSWhyMagic why) const {
- if (!isMagic()) {
- return false;
- }
- MOZ_RELEASE_ASSERT(data.s.payload.why == why);
- return true;
- }
- JS::TraceKind traceKind() const {
- MOZ_ASSERT(isGCThing());
- static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
- "Value type tags must correspond with JS::TraceKinds.");
- static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
- "Value type tags must correspond with JS::TraceKinds.");
- static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
- "Value type tags must correspond with JS::TraceKinds.");
- if (MOZ_UNLIKELY(isPrivateGCThing()))
- return JS::GCThingTraceKind(toGCThing());
- return JS::TraceKind(toTag() & 0x03);
- }
- JSWhyMagic whyMagic() const {
- MOZ_ASSERT(isMagic());
- return data.s.payload.why;
- }
- uint32_t magicUint32() const {
- MOZ_ASSERT(isMagic());
- return data.s.payload.u32;
- }
- /*** Comparison ***/
- bool operator==(const Value& rhs) const {
- return data.asBits == rhs.data.asBits;
- }
- bool operator!=(const Value& rhs) const {
- return data.asBits != rhs.data.asBits;
- }
- friend inline bool SameType(const Value& lhs, const Value& rhs);
- /*** Extract the value's typed payload ***/
- int32_t toInt32() const {
- MOZ_ASSERT(isInt32());
- #if defined(JS_NUNBOX32)
- return data.s.payload.i32;
- #elif defined(JS_PUNBOX64)
- return int32_t(data.asBits);
- #endif
- }
- double toDouble() const {
- MOZ_ASSERT(isDouble());
- return data.asDouble;
- }
- double toNumber() const {
- MOZ_ASSERT(isNumber());
- return isDouble() ? toDouble() : double(toInt32());
- }
- JSString* toString() const {
- MOZ_ASSERT(isString());
- #if defined(JS_NUNBOX32)
- return data.s.payload.str;
- #elif defined(JS_PUNBOX64)
- return reinterpret_cast<JSString*>(data.asBits & JSVAL_PAYLOAD_MASK);
- #endif
- }
- JS::Symbol* toSymbol() const {
- MOZ_ASSERT(isSymbol());
- #if defined(JS_NUNBOX32)
- return data.s.payload.sym;
- #elif defined(JS_PUNBOX64)
- return reinterpret_cast<JS::Symbol*>(data.asBits & JSVAL_PAYLOAD_MASK);
- #endif
- }
- JSObject& toObject() const {
- MOZ_ASSERT(isObject());
- #if defined(JS_NUNBOX32)
- return *data.s.payload.obj;
- #elif defined(JS_PUNBOX64)
- return *toObjectOrNull();
- #endif
- }
- JSObject* toObjectOrNull() const {
- MOZ_ASSERT(isObjectOrNull());
- #if defined(JS_NUNBOX32)
- return data.s.payload.obj;
- #elif defined(JS_PUNBOX64)
- uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK;
- MOZ_ASSERT((ptrBits & 0x7) == 0);
- return reinterpret_cast<JSObject*>(ptrBits);
- #endif
- }
- js::gc::Cell* toGCThing() const {
- MOZ_ASSERT(isGCThing());
- #if defined(JS_NUNBOX32)
- return data.s.payload.cell;
- #elif defined(JS_PUNBOX64)
- uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK;
- MOZ_ASSERT((ptrBits & 0x7) == 0);
- return reinterpret_cast<js::gc::Cell*>(ptrBits);
- #endif
- }
- GCCellPtr toGCCellPtr() const {
- return GCCellPtr(toGCThing(), traceKind());
- }
- bool toBoolean() const {
- MOZ_ASSERT(isBoolean());
- #if defined(JS_NUNBOX32)
- return bool(data.s.payload.boo);
- #elif defined(JS_PUNBOX64)
- return bool(data.asBits & JSVAL_PAYLOAD_MASK);
- #endif
- }
- uint32_t payloadAsRawUint32() const {
- MOZ_ASSERT(!isDouble());
- return data.s.payload.u32;
- }
- uint64_t asRawBits() const {
- return data.asBits;
- }
- JSValueType extractNonDoubleType() const {
- uint32_t type = toTag() & 0xF;
- MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
- return JSValueType(type);
- }
- /*
- * Private API
- *
- * Private setters/getters allow the caller to read/write arbitrary types
- * that fit in the 64-bit payload. It is the caller's responsibility, after
- * storing to a value with setPrivateX to read only using getPrivateX.
- * Privates values are given a type which ensures they are not marked.
- */
- void setPrivate(void* ptr) {
- MOZ_ASSERT((uintptr_t(ptr) & 1) == 0);
- #if defined(JS_NUNBOX32)
- data.s.tag = JSValueTag(0);
- data.s.payload.ptr = ptr;
- #elif defined(JS_PUNBOX64)
- data.asBits = uintptr_t(ptr) >> 1;
- #endif
- MOZ_ASSERT(isDouble());
- }
- void* toPrivate() const {
- MOZ_ASSERT(isDouble());
- #if defined(JS_NUNBOX32)
- return data.s.payload.ptr;
- #elif defined(JS_PUNBOX64)
- MOZ_ASSERT((data.asBits & 0x8000000000000000ULL) == 0);
- return reinterpret_cast<void*>(data.asBits << 1);
- #endif
- }
- void setPrivateUint32(uint32_t ui) {
- MOZ_ASSERT(uint32_t(int32_t(ui)) == ui);
- setInt32(int32_t(ui));
- }
- uint32_t toPrivateUint32() const {
- return uint32_t(toInt32());
- }
- /*
- * Private GC Thing API
- *
- * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit
- * payload as private GC things. Such Values are considered isGCThing(), and
- * as such, automatically marked. Their traceKind() is gotten via their
- * cells.
- */
- void setPrivateGCThing(js::gc::Cell* cell) {
- MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
- "Private GC thing Values must not be strings. Make a StringValue instead.");
- MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
- "Private GC thing Values must not be symbols. Make a SymbolValue instead.");
- MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
- "Private GC thing Values must not be objects. Make an ObjectValue instead.");
- MOZ_ASSERT(uintptr_t(cell) > 0x1000);
- #if defined(JS_PUNBOX64)
- // VisualStudio cannot contain parenthesized C++ style cast and shift
- // inside decltype in template parameter:
- // AssertionConditionType<decltype((uintptr_t(x) >> 1))>
- // It throws syntax error.
- MOZ_ASSERT((((uintptr_t)cell) >> JSVAL_TAG_SHIFT) == 0);
- #endif
- data.asBits = bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING, PayloadType(cell));
- }
- bool isPrivateGCThing() const {
- return toTag() == JSVAL_TAG_PRIVATE_GCTHING;
- }
- const size_t* payloadWord() const {
- #if defined(JS_NUNBOX32)
- return &data.s.payload.word;
- #elif defined(JS_PUNBOX64)
- return &data.asWord;
- #endif
- }
- const uintptr_t* payloadUIntPtr() const {
- #if defined(JS_NUNBOX32)
- return &data.s.payload.uintptr;
- #elif defined(JS_PUNBOX64)
- return &data.asUIntPtr;
- #endif
- }
- #if !defined(_MSC_VER) && !defined(__sparc)
- // Value must be POD so that MSVC will pass it by value and not in memory
- // (bug 689101); the same is true for SPARC as well (bug 737344). More
- // precisely, we don't want Value return values compiled as out params.
- private:
- #endif
- #if MOZ_LITTLE_ENDIAN
- # if defined(JS_NUNBOX32)
- union layout {
- uint64_t asBits;
- struct {
- union {
- int32_t i32;
- uint32_t u32;
- uint32_t boo; // Don't use |bool| -- it must be four bytes.
- JSString* str;
- JS::Symbol* sym;
- JSObject* obj;
- js::gc::Cell* cell;
- void* ptr;
- JSWhyMagic why;
- size_t word;
- uintptr_t uintptr;
- } payload;
- JSValueTag tag;
- } s;
- double asDouble;
- void* asPtr;
- layout() : asBits(JSVAL_RAW64_UNDEFINED) {}
- explicit constexpr layout(uint64_t bits) : asBits(bits) {}
- explicit constexpr layout(double d) : asDouble(d) {}
- } data;
- # elif defined(JS_PUNBOX64)
- union layout {
- uint64_t asBits;
- #if !defined(_WIN64)
- /* MSVC does not pack these correctly :-( */
- struct {
- uint64_t payload47 : 47;
- JSValueTag tag : 17;
- } debugView;
- #endif
- struct {
- union {
- int32_t i32;
- uint32_t u32;
- JSWhyMagic why;
- } payload;
- } s;
- double asDouble;
- void* asPtr;
- size_t asWord;
- uintptr_t asUIntPtr;
- layout() : asBits(JSVAL_RAW64_UNDEFINED) {}
- explicit constexpr layout(uint64_t bits) : asBits(bits) {}
- explicit constexpr layout(double d) : asDouble(d) {}
- } data;
- # endif /* JS_PUNBOX64 */
- #else /* MOZ_LITTLE_ENDIAN */
- # if defined(JS_NUNBOX32)
- union layout {
- uint64_t asBits;
- struct {
- JSValueTag tag;
- union {
- int32_t i32;
- uint32_t u32;
- uint32_t boo; // Don't use |bool| -- it must be four bytes.
- JSString* str;
- JS::Symbol* sym;
- JSObject* obj;
- js::gc::Cell* cell;
- void* ptr;
- JSWhyMagic why;
- size_t word;
- uintptr_t uintptr;
- } payload;
- } s;
- double asDouble;
- void* asPtr;
- layout() : asBits(JSVAL_RAW64_UNDEFINED) {}
- explicit constexpr layout(uint64_t bits) : asBits(bits) {}
- explicit constexpr layout(double d) : asDouble(d) {}
- } data;
- # elif defined(JS_PUNBOX64)
- union layout {
- uint64_t asBits;
- struct {
- JSValueTag tag : 17;
- uint64_t payload47 : 47;
- } debugView;
- struct {
- uint32_t padding;
- union {
- int32_t i32;
- uint32_t u32;
- JSWhyMagic why;
- } payload;
- } s;
- double asDouble;
- void* asPtr;
- size_t asWord;
- uintptr_t asUIntPtr;
- layout() : asBits(JSVAL_RAW64_UNDEFINED) {}
- explicit constexpr layout(uint64_t bits) : asBits(bits) {}
- explicit constexpr layout(double d) : asDouble(d) {}
- } data;
- # endif /* JS_PUNBOX64 */
- #endif /* MOZ_LITTLE_ENDIAN */
- private:
- explicit constexpr Value(uint64_t asBits) : data(asBits) {}
- explicit constexpr Value(double d) : data(d) {}
- void staticAssertions() {
- JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
- JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
- JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4);
- JS_STATIC_ASSERT(sizeof(Value) == 8);
- }
- friend constexpr Value JS::UndefinedValue();
- public:
- static constexpr uint64_t
- bitsFromTagAndPayload(JSValueTag tag, PayloadType payload)
- {
- #if defined(JS_NUNBOX32)
- return (uint64_t(uint32_t(tag)) << 32) | payload;
- #elif defined(JS_PUNBOX64)
- return (uint64_t(uint32_t(tag)) << JSVAL_TAG_SHIFT) | payload;
- #endif
- }
- static constexpr Value
- fromTagAndPayload(JSValueTag tag, PayloadType payload)
- {
- return fromRawBits(bitsFromTagAndPayload(tag, payload));
- }
- static constexpr Value
- fromRawBits(uint64_t asBits) {
- return Value(asBits);
- }
- static constexpr Value
- fromInt32(int32_t i) {
- return fromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
- }
- static constexpr Value
- fromDouble(double d) {
- return Value(d);
- }
- } JS_HAZ_GC_POINTER;
- /**
- * This is a null-constructible structure that can convert to and from
- * a Value, allowing UninitializedValue to be stored in unions.
- */
- struct MOZ_NON_PARAM alignas(8) UninitializedValue
- {
- private:
- uint64_t bits;
- public:
- UninitializedValue() = default;
- UninitializedValue(const UninitializedValue&) = default;
- MOZ_IMPLICIT UninitializedValue(const Value& val) : bits(val.asRawBits()) {}
- inline uint64_t asRawBits() const {
- return bits;
- }
- inline Value& asValueRef() {
- return *reinterpret_cast<Value*>(this);
- }
- inline const Value& asValueRef() const {
- return *reinterpret_cast<const Value*>(this);
- }
- inline operator Value&() {
- return asValueRef();
- }
- inline operator Value const&() const {
- return asValueRef();
- }
- inline operator Value() const {
- return asValueRef();
- }
- inline void operator=(Value const& other) {
- asValueRef() = other;
- }
- };
- static_assert(sizeof(Value) == 8, "Value size must leave three tag bits, be a binary power, and is ubiquitously depended upon everywhere");
- static_assert(sizeof(UninitializedValue) == sizeof(Value), "Value and UninitializedValue must be the same size");
- static_assert(alignof(UninitializedValue) == alignof(Value), "Value and UninitializedValue must have same alignment");
- inline bool
- IsOptimizedPlaceholderMagicValue(const Value& v)
- {
- if (v.isMagic()) {
- MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT);
- return true;
- }
- return false;
- }
- static MOZ_ALWAYS_INLINE void
- ExposeValueToActiveJS(const Value& v)
- {
- if (v.isGCThing())
- js::gc::ExposeGCThingToActiveJS(GCCellPtr(v));
- }
- /************************************************************************/
- static inline Value
- NullValue()
- {
- Value v;
- v.setNull();
- return v;
- }
- static inline constexpr Value
- UndefinedValue()
- {
- return Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
- }
- static inline constexpr Value
- Int32Value(int32_t i32)
- {
- return Value::fromInt32(i32);
- }
- static inline Value
- DoubleValue(double dbl)
- {
- Value v;
- v.setDouble(dbl);
- return v;
- }
- static inline Value
- CanonicalizedDoubleValue(double d)
- {
- return MOZ_UNLIKELY(mozilla::IsNaN(d))
- ? Value::fromRawBits(detail::CanonicalizedNaNBits)
- : Value::fromDouble(d);
- }
- static inline bool
- IsCanonicalized(double d)
- {
- if (mozilla::IsInfinite(d) || mozilla::IsFinite(d))
- return true;
- uint64_t bits;
- mozilla::BitwiseCast<uint64_t>(d, &bits);
- return (bits & ~mozilla::DoubleTypeTraits::kSignBit) == detail::CanonicalizedNaNBits;
- }
- static inline Value
- DoubleNaNValue()
- {
- Value v;
- v.setNaN();
- return v;
- }
- static inline Value
- Float32Value(float f)
- {
- Value v;
- v.setDouble(f);
- return v;
- }
- static inline Value
- StringValue(JSString* str)
- {
- Value v;
- v.setString(str);
- return v;
- }
- static inline Value
- SymbolValue(JS::Symbol* sym)
- {
- Value v;
- v.setSymbol(sym);
- return v;
- }
- static inline Value
- BooleanValue(bool boo)
- {
- Value v;
- v.setBoolean(boo);
- return v;
- }
- static inline Value
- TrueValue()
- {
- Value v;
- v.setBoolean(true);
- return v;
- }
- static inline Value
- FalseValue()
- {
- Value v;
- v.setBoolean(false);
- return v;
- }
- static inline Value
- ObjectValue(JSObject& obj)
- {
- Value v;
- v.setObject(obj);
- return v;
- }
- static inline Value
- ObjectValueCrashOnTouch()
- {
- Value v;
- v.setObject(*reinterpret_cast<JSObject*>(0x48));
- return v;
- }
- static inline Value
- MagicValue(JSWhyMagic why)
- {
- Value v;
- v.setMagic(why);
- return v;
- }
- static inline Value
- MagicValueUint32(uint32_t payload)
- {
- Value v;
- v.setMagicUint32(payload);
- return v;
- }
- static inline Value
- NumberValue(float f)
- {
- Value v;
- v.setNumber(f);
- return v;
- }
- static inline Value
- NumberValue(double dbl)
- {
- Value v;
- v.setNumber(dbl);
- return v;
- }
- static inline Value
- NumberValue(int8_t i)
- {
- return Int32Value(i);
- }
- static inline Value
- NumberValue(uint8_t i)
- {
- return Int32Value(i);
- }
- static inline Value
- NumberValue(int16_t i)
- {
- return Int32Value(i);
- }
- static inline Value
- NumberValue(uint16_t i)
- {
- return Int32Value(i);
- }
- static inline Value
- NumberValue(int32_t i)
- {
- return Int32Value(i);
- }
- static inline constexpr Value
- NumberValue(uint32_t i)
- {
- return i <= JSVAL_INT_MAX
- ? Int32Value(int32_t(i))
- : Value::fromDouble(double(i));
- }
- namespace detail {
- template <bool Signed>
- class MakeNumberValue
- {
- public:
- template<typename T>
- static inline Value create(const T t)
- {
- Value v;
- if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX)
- v.setInt32(int32_t(t));
- else
- v.setDouble(double(t));
- return v;
- }
- };
- template <>
- class MakeNumberValue<false>
- {
- public:
- template<typename T>
- static inline Value create(const T t)
- {
- Value v;
- if (t <= JSVAL_INT_MAX)
- v.setInt32(int32_t(t));
- else
- v.setDouble(double(t));
- return v;
- }
- };
- } // namespace detail
- template <typename T>
- static inline Value
- NumberValue(const T t)
- {
- MOZ_ASSERT(Value::isNumberRepresentable(t), "value creation would be lossy");
- return detail::MakeNumberValue<std::numeric_limits<T>::is_signed>::create(t);
- }
- static inline Value
- ObjectOrNullValue(JSObject* obj)
- {
- Value v;
- v.setObjectOrNull(obj);
- return v;
- }
- static inline Value
- PrivateValue(void* ptr)
- {
- Value v;
- v.setPrivate(ptr);
- return v;
- }
- static inline Value
- PrivateUint32Value(uint32_t ui)
- {
- Value v;
- v.setPrivateUint32(ui);
- return v;
- }
- static inline Value
- PrivateGCThingValue(js::gc::Cell* cell)
- {
- Value v;
- v.setPrivateGCThing(cell);
- return v;
- }
- static inline Value
- PoisonedObjectValue(JSObject* obj)
- {
- Value v;
- v.setObjectNoCheck(obj);
- return v;
- }
- inline bool
- SameType(const Value& lhs, const Value& rhs)
- {
- #if defined(JS_NUNBOX32)
- JSValueTag ltag = lhs.toTag(), rtag = rhs.toTag();
- return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
- #elif defined(JS_PUNBOX64)
- return (lhs.isDouble() && rhs.isDouble()) ||
- (((lhs.data.asBits ^ rhs.data.asBits) & 0xFFFF800000000000ULL) == 0);
- #endif
- }
- } // namespace JS
- /************************************************************************/
- namespace JS {
- JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const Value& next);
- template <>
- struct GCPolicy<JS::Value>
- {
- static Value initial() { return UndefinedValue(); }
- static void trace(JSTracer* trc, Value* v, const char* name) {
- js::UnsafeTraceManuallyBarrieredEdge(trc, v, name);
- }
- static bool isTenured(const Value& thing) {
- return !thing.isGCThing() || !IsInsideNursery(thing.toGCThing());
- }
- };
- } // namespace JS
- namespace js {
- template <>
- struct BarrierMethods<JS::Value>
- {
- static gc::Cell* asGCThingOrNull(const JS::Value& v) {
- return v.isGCThing() ? v.toGCThing() : nullptr;
- }
- static void postBarrier(JS::Value* v, const JS::Value& prev, const JS::Value& next) {
- JS::HeapValuePostBarrier(v, prev, next);
- }
- static void exposeToJS(const JS::Value& v) {
- JS::ExposeValueToActiveJS(v);
- }
- };
- template <class Outer> class MutableValueOperations;
- /**
- * A class designed for CRTP use in implementing the non-mutating parts of the
- * Value interface in Value-like classes. Outer must be a class inheriting
- * ValueOperations<Outer> with a visible get() method returning a const
- * reference to the Value abstracted by Outer.
- */
- template <class Outer>
- class ValueOperations
- {
- friend class MutableValueOperations<Outer>;
- const JS::Value& value() const { return static_cast<const Outer*>(this)->get(); }
- public:
- bool isUndefined() const { return value().isUndefined(); }
- bool isNull() const { return value().isNull(); }
- bool isBoolean() const { return value().isBoolean(); }
- bool isTrue() const { return value().isTrue(); }
- bool isFalse() const { return value().isFalse(); }
- bool isNumber() const { return value().isNumber(); }
- bool isInt32() const { return value().isInt32(); }
- bool isInt32(int32_t i32) const { return value().isInt32(i32); }
- bool isDouble() const { return value().isDouble(); }
- bool isString() const { return value().isString(); }
- bool isSymbol() const { return value().isSymbol(); }
- bool isObject() const { return value().isObject(); }
- bool isMagic() const { return value().isMagic(); }
- bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
- bool isGCThing() const { return value().isGCThing(); }
- bool isPrimitive() const { return value().isPrimitive(); }
- bool isNullOrUndefined() const { return value().isNullOrUndefined(); }
- bool isObjectOrNull() const { return value().isObjectOrNull(); }
- bool toBoolean() const { return value().toBoolean(); }
- double toNumber() const { return value().toNumber(); }
- int32_t toInt32() const { return value().toInt32(); }
- double toDouble() const { return value().toDouble(); }
- JSString* toString() const { return value().toString(); }
- JS::Symbol* toSymbol() const { return value().toSymbol(); }
- JSObject& toObject() const { return value().toObject(); }
- JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
- gc::Cell* toGCThing() const { return value().toGCThing(); }
- JS::TraceKind traceKind() const { return value().traceKind(); }
- void* toPrivate() const { return value().toPrivate(); }
- uint32_t toPrivateUint32() const { return value().toPrivateUint32(); }
- uint64_t asRawBits() const { return value().asRawBits(); }
- JSValueType extractNonDoubleType() const { return value().extractNonDoubleType(); }
- JSWhyMagic whyMagic() const { return value().whyMagic(); }
- uint32_t magicUint32() const { return value().magicUint32(); }
- };
- /**
- * A class designed for CRTP use in implementing all the mutating parts of the
- * Value interface in Value-like classes. Outer must be a class inheriting
- * MutableValueOperations<Outer> with visible get() methods returning const and
- * non-const references to the Value abstracted by Outer.
- */
- template <class Outer>
- class MutableValueOperations : public ValueOperations<Outer>
- {
- protected:
- void set(const JS::Value& v) {
- // Call Outer::set to trigger any barriers.
- static_cast<Outer*>(this)->set(v);
- }
- public:
- void setNull() { set(JS::NullValue()); }
- void setUndefined() { set(JS::UndefinedValue()); }
- void setInt32(int32_t i) { set(JS::Int32Value(i)); }
- void setDouble(double d) { set(JS::DoubleValue(d)); }
- void setNaN() { setDouble(JS::GenericNaN()); }
- void setBoolean(bool b) { set(JS::BooleanValue(b)); }
- void setMagic(JSWhyMagic why) { set(JS::MagicValue(why)); }
- void setNumber(uint32_t ui) { set(JS::NumberValue(ui)); }
- void setNumber(double d) { set(JS::NumberValue(d)); }
- void setString(JSString* str) { set(JS::StringValue(str)); }
- void setSymbol(JS::Symbol* sym) { set(JS::SymbolValue(sym)); }
- void setObject(JSObject& obj) { set(JS::ObjectValue(obj)); }
- void setObjectOrNull(JSObject* arg) { set(JS::ObjectOrNullValue(arg)); }
- void setPrivate(void* ptr) { set(JS::PrivateValue(ptr)); }
- void setPrivateUint32(uint32_t ui) { set(JS::PrivateUint32Value(ui)); }
- void setPrivateGCThing(js::gc::Cell* cell) { set(JS::PrivateGCThingValue(cell)); }
- };
- /*
- * Augment the generic Heap<T> interface when T = Value with
- * type-querying, value-extracting, and mutating operations.
- */
- template <>
- class HeapBase<JS::Value> : public MutableValueOperations<JS::Heap<JS::Value> >
- {
- typedef JS::Heap<JS::Value> Outer;
- friend class ValueOperations<Outer>;
- public:
- void setNumber(uint32_t ui) {
- if (ui > JSVAL_INT_MAX) {
- this->setDouble((double)ui);
- } else {
- this->setInt32((int32_t)ui);
- }
- }
- void setNumber(double d) {
- int32_t i;
- if (mozilla::NumberIsInt32(d, &i)) {
- this->setInt32(i);
- } else {
- this->setDouble(d);
- }
- }
- };
- template <>
- class HandleBase<JS::Value> : public ValueOperations<JS::Handle<JS::Value> >
- {};
- template <>
- class MutableHandleBase<JS::Value> : public MutableValueOperations<JS::MutableHandle<JS::Value> >
- {};
- template <>
- class RootedBase<JS::Value> : public MutableValueOperations<JS::Rooted<JS::Value> >
- {};
- template <>
- class PersistentRootedBase<JS::Value> : public MutableValueOperations<JS::PersistentRooted<JS::Value>>
- {};
- /*
- * If the Value is a GC pointer type, convert to that type and call |f| with
- * the pointer. If the Value is not a GC type, calls F::defaultValue.
- */
- template <typename F, typename... Args>
- auto
- DispatchTyped(F f, const JS::Value& val, Args&&... args)
- -> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
- {
- if (val.isString())
- return f(val.toString(), mozilla::Forward<Args>(args)...);
- if (val.isObject())
- return f(&val.toObject(), mozilla::Forward<Args>(args)...);
- if (val.isSymbol())
- return f(val.toSymbol(), mozilla::Forward<Args>(args)...);
- if (MOZ_UNLIKELY(val.isPrivateGCThing()))
- return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward<Args>(args)...);
- MOZ_ASSERT(!val.isGCThing());
- return F::defaultValue(val);
- }
- template <class S> struct VoidDefaultAdaptor { static void defaultValue(const S&) {} };
- template <class S> struct IdentityDefaultAdaptor { static S defaultValue(const S& v) {return v;} };
- template <class S, bool v> struct BoolDefaultAdaptor { static bool defaultValue(const S&) { return v; } };
- } // namespace js
- /************************************************************************/
- namespace JS {
- extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue;
- extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue;
- extern JS_PUBLIC_DATA(const HandleValue) TrueHandleValue;
- extern JS_PUBLIC_DATA(const HandleValue) FalseHandleValue;
- } // namespace JS
- #endif /* js_Value_h */
|