LCOV - code coverage report
Current view: top level - js/public - Value.h (source / functions) Hit Total Coverage
Test: output.info Lines: 374 420 89.0 %
Date: 2017-07-14 16:53:18 Functions: 247 294 84.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13