tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Value.cpp (7484B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      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 #include "js/Value.h"
      8 
      9 #include "mozilla/Assertions.h"
     10 
     11 #include <inttypes.h>
     12 
     13 #include "gc/Cell.h"         // js::gc::Cell
     14 #include "js/Conversions.h"  // JS::NumberToString, JS::MaximumNumberToStringLength
     15 #include "js/Printer.h"      // js::GenericPrinter, js::Fprinter
     16 #include "vm/BigIntType.h"   // JS::BigInt
     17 #include "vm/JSObject.h"     // JSObject
     18 #include "vm/JSONPrinter.h"  // js::JSONPrinter
     19 #include "vm/StringType.h"   // JSString
     20 #include "vm/SymbolType.h"   // JS::Symbol
     21 
     22 static const JS::Value JSVAL_NULL =
     23    JS::Value::fromTagAndPayload(JSVAL_TAG_NULL, 0);
     24 static const JS::Value JSVAL_FALSE =
     25    JS::Value::fromTagAndPayload(JSVAL_TAG_BOOLEAN, false);
     26 static const JS::Value JSVAL_TRUE =
     27    JS::Value::fromTagAndPayload(JSVAL_TAG_BOOLEAN, true);
     28 static const JS::Value JSVAL_VOID =
     29    JS::Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
     30 static const mozilla::Maybe<JS::Value> JSVAL_NOTHING;
     31 
     32 namespace JS {
     33 
     34 const HandleValue NullHandleValue =
     35    HandleValue::fromMarkedLocation(&JSVAL_NULL);
     36 const HandleValue UndefinedHandleValue =
     37    HandleValue::fromMarkedLocation(&JSVAL_VOID);
     38 const HandleValue TrueHandleValue =
     39    HandleValue::fromMarkedLocation(&JSVAL_TRUE);
     40 const HandleValue FalseHandleValue =
     41    HandleValue::fromMarkedLocation(&JSVAL_FALSE);
     42 const Handle<mozilla::Maybe<Value>> NothingHandleValue =
     43    Handle<mozilla::Maybe<Value>>::fromMarkedLocation(&JSVAL_NOTHING);
     44 
     45 #ifdef DEBUG
     46 void JS::Value::assertTraceKindMatches(js::gc::Cell* cell) const {
     47  MOZ_ASSERT(traceKind() == cell->getTraceKind());
     48 }
     49 #endif
     50 
     51 }  // namespace JS
     52 
     53 void js::ReportBadValueTypeAndCrash(const JS::Value& value) {
     54  MOZ_CRASH_UNSAFE_PRINTF("JS::Value has illegal type: 0x%" PRIx64,
     55                          value.asRawBits());
     56 }
     57 
     58 #if defined(DEBUG) || defined(JS_JITSPEW)
     59 void JS::Value::dump() const {
     60  js::Fprinter out(stderr);
     61  dump(out);
     62 }
     63 
     64 void JS::Value::dump(js::GenericPrinter& out) const {
     65  js::JSONPrinter json(out);
     66  dump(json);
     67  out.put("\n");
     68 }
     69 
     70 void JS::Value::dump(js::JSONPrinter& json) const {
     71  json.beginObject();
     72  dumpFields(json);
     73  json.endObject();
     74 }
     75 
     76 template <typename KnownF, typename UnknownF>
     77 void WhyMagicToString(JSWhyMagic why, KnownF known, UnknownF unknown) {
     78  switch (why) {
     79    case JS_ELEMENTS_HOLE:
     80      known("JS_ELEMENTS_HOLE");
     81      break;
     82    case JS_NO_ITER_VALUE:
     83      known("JS_NO_ITER_VALUE");
     84      break;
     85    case JS_GENERATOR_CLOSING:
     86      known("JS_GENERATOR_CLOSING");
     87      break;
     88    case JS_ARG_POISON:
     89      known("JS_ARG_POISON");
     90      break;
     91    case JS_SERIALIZE_NO_NODE:
     92      known("JS_SERIALIZE_NO_NODE");
     93      break;
     94    case JS_IS_CONSTRUCTING:
     95      known("JS_IS_CONSTRUCTING");
     96      break;
     97    case JS_HASH_KEY_EMPTY:
     98      known("JS_HASH_KEY_EMPTY");
     99      break;
    100    case JS_ION_ERROR:
    101      known("JS_ION_ERROR");
    102      break;
    103    case JS_ION_BAILOUT:
    104      known("JS_ION_BAILOUT");
    105      break;
    106    case JS_OPTIMIZED_OUT:
    107      known("JS_OPTIMIZED_OUT");
    108      break;
    109    case JS_UNINITIALIZED_LEXICAL:
    110      known("JS_UNINITIALIZED_LEXICAL");
    111      break;
    112    case JS_MISSING_ARGUMENTS:
    113      known("JS_MISSING_ARGUMENTS");
    114      break;
    115    case JS_GENERIC_MAGIC:
    116      known("JS_GENERIC_MAGIC");
    117      break;
    118    case JS_ERROR_WITHOUT_CAUSE:
    119      known("JS_ERROR_WITHOUT_CAUSE");
    120      break;
    121    default:
    122      unknown(int(why));
    123      break;
    124  }
    125 }
    126 
    127 void JS::Value::dumpFields(js::JSONPrinter& json) const {
    128  if (isDouble()) {
    129    json.property("type", "double");
    130    double d = toDouble();
    131 
    132    if (mozilla::IsNegativeZero(d)) {
    133      // Negative zero needs special handling.
    134      json.property("value", "-0");
    135    } else {
    136      // Infinity, -Infinity, NaN are handled by JS::NumberToString.
    137      char buf[JS::MaximumNumberToStringLength];
    138      JS::NumberToString(d, buf);
    139      json.property("value", buf);
    140    }
    141 
    142    json.formatProperty("private", "0x%p", toPrivateUnchecked());
    143  } else {
    144    auto tag = toTag();
    145    switch (tag) {
    146      case JSVAL_TAG_INT32:
    147        json.property("type", "int32");
    148        json.property("value", toInt32());
    149        break;
    150      case JSVAL_TAG_UNDEFINED:
    151        json.property("type", "undefined");
    152        break;
    153      case JSVAL_TAG_NULL:
    154        json.property("type", "null");
    155        break;
    156      case JSVAL_TAG_BOOLEAN:
    157        json.property("type", "boolean");
    158        json.boolProperty("value", toBoolean());
    159        break;
    160      case JSVAL_TAG_MAGIC:
    161        json.property("type", "magic");
    162        WhyMagicToString(
    163            whyMagic(), [&](const char* name) { json.property("value", name); },
    164            [&](int value) {
    165              json.formatProperty("value", "Unknown(%d)", value);
    166            });
    167        break;
    168      case JSVAL_TAG_STRING:
    169        json.property("type", "string");
    170        toString()->dumpFields(json);
    171        break;
    172      case JSVAL_TAG_SYMBOL:
    173        json.property("type", "symbol");
    174        toSymbol()->dumpFields(json);
    175        break;
    176      case JSVAL_TAG_PRIVATE_GCTHING:
    177        json.property("type", "private GCThing");
    178        json.formatProperty("address", "0x%p", toGCThing());
    179        break;
    180      case JSVAL_TAG_BIGINT:
    181        json.property("type", "bigint");
    182        toBigInt()->dumpFields(json);
    183        break;
    184      case JSVAL_TAG_OBJECT:
    185        json.property("type", "object");
    186        toObject().dumpFields(json);
    187        break;
    188      default:
    189        json.formatProperty("type", "unknown tag(%08x)", tag);
    190        break;
    191    }
    192  }
    193 }
    194 
    195 void JS::Value::dumpStringContent(js::GenericPrinter& out) const {
    196  if (isDouble()) {
    197    double d = toDouble();
    198 
    199    if (mozilla::IsNegativeZero(d)) {
    200      // Negative zero needs special handling.
    201      out.put("-0");
    202    } else {
    203      // Infinity, -Infinity, NaN are handled by JS::NumberToString.
    204      char buf[JS::MaximumNumberToStringLength];
    205      JS::NumberToString(d, buf);
    206      out.put(buf);
    207    }
    208 
    209    out.printf(" / <private @ 0x%p>", toPrivateUnchecked());
    210  } else {
    211    auto tag = toTag();
    212    switch (tag) {
    213      case JSVAL_TAG_INT32:
    214        out.printf("%d", toInt32());
    215        break;
    216      case JSVAL_TAG_UNDEFINED:
    217        out.put("undefined");
    218        break;
    219      case JSVAL_TAG_NULL:
    220        out.put("null");
    221        break;
    222      case JSVAL_TAG_BOOLEAN:
    223        if (toBoolean()) {
    224          out.put("true");
    225        } else {
    226          out.put("false");
    227        }
    228        break;
    229      case JSVAL_TAG_MAGIC:
    230        out.put("<magic ");
    231        WhyMagicToString(
    232            whyMagic(), [&](const char* name) { out.put(name); },
    233            [&](int value) { out.printf("Unknown(%d)", value); });
    234        out.put(">");
    235        break;
    236      case JSVAL_TAG_STRING:
    237        toString()->dumpStringContent(out);
    238        break;
    239      case JSVAL_TAG_SYMBOL:
    240        toSymbol()->dumpStringContent(out);
    241        break;
    242      case JSVAL_TAG_PRIVATE_GCTHING:
    243        out.printf("<private GCThing @ 0x%p>", toGCThing());
    244        break;
    245      case JSVAL_TAG_BIGINT:
    246        toBigInt()->dumpStringContent(out);
    247        break;
    248      case JSVAL_TAG_OBJECT:
    249        toObject().dumpStringContent(out);
    250        break;
    251      default:
    252        out.printf("Unknown(%08x)", tag);
    253        break;
    254    }
    255  }
    256 }
    257 #endif