tor-browser

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

SymbolType.cpp (5793B)


      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 "vm/SymbolType.h"
      8 
      9 #include "gc/HashUtil.h"
     10 #include "js/Printer.h"  // js::GenericPrinter, js::Fprinter
     11 #include "util/StringBuilder.h"
     12 #include "vm/JSContext.h"
     13 #include "vm/JSONPrinter.h"  // js::JSONPrinter
     14 #include "vm/Realm.h"
     15 
     16 #include "vm/Realm-inl.h"
     17 
     18 using JS::Symbol;
     19 using namespace js;
     20 
     21 Symbol* Symbol::newInternal(JSContext* cx, JS::SymbolCode code, uint32_t hash,
     22                            Handle<JSAtom*> description) {
     23  MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
     24  AutoAllocInAtomsZone az(cx);
     25  return cx->newCell<Symbol>(code, hash, description);
     26 }
     27 
     28 Symbol* Symbol::new_(JSContext* cx, JS::SymbolCode code,
     29                     HandleString description) {
     30  Rooted<JSAtom*> atom(cx);
     31  if (description) {
     32    atom = AtomizeString(cx, description);
     33    if (!atom) {
     34      return nullptr;
     35    }
     36  }
     37 
     38  Symbol* sym = newInternal(cx, code, cx->runtime()->randomHashCode(), atom);
     39  if (sym) {
     40    cx->markAtom(sym);
     41  }
     42  return sym;
     43 }
     44 
     45 Symbol* Symbol::newWellKnown(JSContext* cx, JS::SymbolCode code,
     46                             Handle<PropertyName*> description) {
     47  return newInternal(cx, code, cx->runtime()->randomHashCode(), description);
     48 }
     49 
     50 Symbol* Symbol::for_(JSContext* cx, HandleString description) {
     51  Rooted<JSAtom*> atom(cx, AtomizeString(cx, description));
     52  if (!atom) {
     53    return nullptr;
     54  }
     55 
     56  SymbolRegistry& registry = cx->symbolRegistry();
     57  DependentAddPtr<SymbolRegistry> p(cx, registry, atom);
     58  if (p) {
     59    cx->markAtom(*p);
     60    return *p;
     61  }
     62 
     63  // Rehash the hash of the atom to give the corresponding symbol a hash
     64  // that is different than the hash of the corresponding atom.
     65  HashNumber hash = mozilla::HashGeneric(atom->hash());
     66  Symbol* sym = newInternal(cx, SymbolCode::InSymbolRegistry, hash, atom);
     67  if (!sym) {
     68    return nullptr;
     69  }
     70 
     71  if (!p.add(cx, registry, atom, sym)) {
     72    return nullptr;
     73  }
     74 
     75  cx->markAtom(sym);
     76  return sym;
     77 }
     78 
     79 #if defined(DEBUG) || defined(JS_JITSPEW)
     80 void Symbol::dump() const {
     81  js::Fprinter out(stderr);
     82  dump(out);
     83 }
     84 
     85 void Symbol::dump(js::GenericPrinter& out) const {
     86  js::JSONPrinter json(out);
     87  dump(json);
     88  out.put("\n");
     89 }
     90 
     91 void Symbol::dump(js::JSONPrinter& json) const {
     92  json.beginObject();
     93  dumpFields(json);
     94  json.endObject();
     95 }
     96 
     97 template <typename KnownF, typename UnknownF>
     98 void SymbolCodeToString(JS::SymbolCode code, KnownF known, UnknownF unknown) {
     99  switch (code) {
    100 #  define DEFINE_CASE(name)    \
    101    case JS::SymbolCode::name: \
    102      known(#name);            \
    103      break;
    104    JS_FOR_EACH_WELL_KNOWN_SYMBOL(DEFINE_CASE)
    105 #  undef DEFINE_CASE
    106 
    107    case JS::SymbolCode::Limit:
    108      known("Limit");
    109      break;
    110    case JS::SymbolCode::WellKnownAPILimit:
    111      known("WellKnownAPILimit");
    112      break;
    113    case JS::SymbolCode::PrivateNameSymbol:
    114      known("PrivateNameSymbol");
    115      break;
    116    case JS::SymbolCode::InSymbolRegistry:
    117      known("InSymbolRegistry");
    118      break;
    119    case JS::SymbolCode::UniqueSymbol:
    120      known("UniqueSymbol");
    121      break;
    122    default:
    123      unknown(uint32_t(code));
    124      break;
    125  }
    126 }
    127 
    128 void Symbol::dumpFields(js::JSONPrinter& json) const {
    129  json.formatProperty("address", "(JS::Symbol*)0x%p", this);
    130 
    131  SymbolCodeToString(
    132      code_, [&](const char* name) { json.property("code", name); },
    133      [&](uint32_t code) {
    134        json.formatProperty("code", "Unknown(%08x)", code);
    135      });
    136 
    137  json.formatProperty("hash", "0x%08x", hash());
    138 
    139  if (description()) {
    140    js::GenericPrinter& out = json.beginStringProperty("description");
    141    description()->dumpCharsNoQuote(out);
    142    json.endStringProperty();
    143  } else {
    144    json.nullProperty("description");
    145  }
    146 }
    147 
    148 void Symbol::dumpStringContent(js::GenericPrinter& out) const {
    149  dumpPropertyName(out);
    150 
    151  if (!isWellKnownSymbol()) {
    152    out.printf(" @ (JS::Symbol*)0x%p", this);
    153  }
    154 }
    155 
    156 void Symbol::dumpPropertyName(js::GenericPrinter& out) const {
    157  if (isWellKnownSymbol()) {
    158    // All the well-known symbol names are ASCII.
    159    description()->dumpCharsNoQuote(out);
    160  } else if (code_ == SymbolCode::InSymbolRegistry ||
    161             code_ == SymbolCode::UniqueSymbol) {
    162    out.printf(code_ == SymbolCode::InSymbolRegistry ? "Symbol.for("
    163                                                     : "Symbol(");
    164 
    165    if (description()) {
    166      description()->dumpCharsSingleQuote(out);
    167    } else {
    168      out.printf("undefined");
    169    }
    170 
    171    out.putChar(')');
    172  } else if (code_ == SymbolCode::PrivateNameSymbol) {
    173    MOZ_ASSERT(description());
    174    out.putChar('#');
    175    description()->dumpCharsNoQuote(out);
    176  } else {
    177    out.printf("<Invalid Symbol code=%u>", unsigned(code_));
    178  }
    179 }
    180 #endif  // defined(DEBUG) || defined(JS_JITSPEW)
    181 
    182 bool js::SymbolDescriptiveString(JSContext* cx, Symbol* sym,
    183                                 MutableHandleValue result) {
    184  // steps 2-5
    185  JSStringBuilder sb(cx);
    186  if (!sb.append("Symbol(")) {
    187    return false;
    188  }
    189  if (JSAtom* desc = sym->description()) {
    190    if (!sb.append(desc)) {
    191      return false;
    192    }
    193  }
    194  if (!sb.append(')')) {
    195    return false;
    196  }
    197 
    198  // step 6
    199  JSString* str = sb.finishString();
    200  if (!str) {
    201    return false;
    202  }
    203  result.setString(str);
    204  return true;
    205 }
    206 
    207 JS::ubi::Node::Size JS::ubi::Concrete<JS::Symbol>::size(
    208    mozilla::MallocSizeOf mallocSizeOf) const {
    209  // If we start allocating symbols in the nursery, we will need to update
    210  // this method.
    211  MOZ_ASSERT(get().isTenured());
    212  return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
    213 }