js/src/vm/SymbolType.cpp
author André Bargull <andre.bargull@gmail.com>
Tue, 02 Jun 2020 20:57:34 +0000
changeset 597698 0880c9f6821008953ea4f4f12d2d6ee84767a636
parent 597585 023c0fdf6679bde4ba0772ff5c060c371e2f268e
permissions -rw-r--r--
Bug 1635839 - Part 1: Add PrivateName Symbol code. r=jorendorff Differential Revision: https://phabricator.services.mozilla.com/D74102

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "vm/SymbolType.h"

#include "builtin/Symbol.h"
#include "gc/Allocator.h"
#include "gc/HashUtil.h"
#include "gc/Rooting.h"
#include "util/StringBuffer.h"
#include "vm/JSContext.h"
#include "vm/Realm.h"

#include "vm/Realm-inl.h"

using JS::Symbol;
using namespace js;

Symbol* Symbol::newInternal(JSContext* cx, JS::SymbolCode code, uint32_t hash,
                            HandleAtom description) {
  MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
  AutoAllocInAtomsZone az(cx);

  Symbol* p = Allocate<JS::Symbol>(cx);
  if (!p) {
    return nullptr;
  }
  return new (p) Symbol(code, hash, description);
}

Symbol* Symbol::new_(JSContext* cx, JS::SymbolCode code,
                     HandleString description) {
  RootedAtom atom(cx);
  if (description) {
    atom = AtomizeString(cx, description);
    if (!atom) {
      return nullptr;
    }
  }

  Symbol* sym = newInternal(cx, code, cx->runtime()->randomHashCode(), atom);
  if (sym) {
    cx->markAtom(sym);
  }
  return sym;
}

Symbol* Symbol::for_(JSContext* cx, HandleString description) {
  RootedAtom atom(cx, AtomizeString(cx, description));
  if (!atom) {
    return nullptr;
  }

  SymbolRegistry& registry = cx->symbolRegistry();
  DependentAddPtr<SymbolRegistry> p(cx, registry, atom);
  if (p) {
    cx->markAtom(*p);
    return *p;
  }

  // Rehash the hash of the atom to give the corresponding symbol a hash
  // that is different than the hash of the corresponding atom.
  HashNumber hash = mozilla::HashGeneric(atom->hash());
  Symbol* sym = newInternal(cx, SymbolCode::InSymbolRegistry, hash, atom);
  if (!sym) {
    return nullptr;
  }

  if (!p.add(cx, registry, atom, sym)) {
    return nullptr;
  }

  cx->markAtom(sym);
  return sym;
}

#if defined(DEBUG) || defined(JS_JITSPEW)
void Symbol::dump() {
  js::Fprinter out(stderr);
  dump(out);
}

void Symbol::dump(js::GenericPrinter& out) {
  if (isWellKnownSymbol()) {
    // All the well-known symbol names are ASCII.
    description()->dumpCharsNoNewline(out);
  } else if (code_ == SymbolCode::InSymbolRegistry ||
             code_ == SymbolCode::UniqueSymbol) {
    out.printf(code_ == SymbolCode::InSymbolRegistry ? "Symbol.for("
                                                     : "Symbol(");

    if (description()) {
      description()->dumpCharsNoNewline(out);
    } else {
      out.printf("undefined");
    }

    out.putChar(')');

    if (code_ == SymbolCode::UniqueSymbol) {
      out.printf("@%p", (void*)this);
    }
  } else if (code_ == SymbolCode::PrivateNameSymbol) {
    MOZ_ASSERT(description());
    out.putChar('#');
    description()->dumpCharsNoNewline(out);
    out.printf("@%p", (void*)this);
  } else {
    out.printf("<Invalid Symbol code=%u>", unsigned(code_));
  }
}
#endif  // defined(DEBUG) || defined(JS_JITSPEW)

bool js::SymbolDescriptiveString(JSContext* cx, Symbol* sym,
                                 MutableHandleValue result) {
  // steps 2-5
  JSStringBuilder sb(cx);
  if (!sb.append("Symbol(")) {
    return false;
  }
  if (JSAtom* desc = sym->description()) {
    if (!sb.append(desc)) {
      return false;
    }
  }
  if (!sb.append(')')) {
    return false;
  }

  // step 6
  JSString* str = sb.finishString();
  if (!str) {
    return false;
  }
  result.setString(str);
  return true;
}

JS::ubi::Node::Size JS::ubi::Concrete<JS::Symbol>::size(
    mozilla::MallocSizeOf mallocSizeOf) const {
  // If we start allocating symbols in the nursery, we will need to update
  // this method.
  MOZ_ASSERT(get().isTenured());
  return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
}