/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * 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/Symbol.h" #include "jscntxt.h" #include "jscompartment.h" #include "builtin/SymbolObject.h" #include "gc/Allocator.h" #include "gc/Rooting.h" #include "vm/StringBuffer.h" #include "jscompartmentinlines.h" using JS::Symbol; using namespace js; Symbol* Symbol::newInternal(ExclusiveContext* cx, JS::SymbolCode code, uint32_t hash, JSAtom* description, AutoLockForExclusiveAccess& lock) { MOZ_ASSERT(cx->compartment() == cx->atomsCompartment(lock)); // Following js::AtomizeString, we grudgingly forgo last-ditch GC here. Symbol* p = Allocate(cx); if (!p) { ReportOutOfMemory(cx); return nullptr; } return new (p) Symbol(code, hash, description); } Symbol* Symbol::new_(ExclusiveContext* cx, JS::SymbolCode code, JSString* description) { JSAtom* atom = nullptr; if (description) { atom = AtomizeString(cx, description); if (!atom) return nullptr; } // Lock to allocate. If symbol allocation becomes a bottleneck, this can // probably be replaced with an assertion that we're on the main thread. AutoLockForExclusiveAccess lock(cx); AutoCompartment ac(cx, cx->atomsCompartment(lock), &lock); return newInternal(cx, code, cx->compartment()->randomHashCode(), atom, lock); } Symbol* Symbol::for_(js::ExclusiveContext* cx, HandleString description) { JSAtom* atom = AtomizeString(cx, description); if (!atom) return nullptr; AutoLockForExclusiveAccess lock(cx); SymbolRegistry& registry = cx->symbolRegistry(lock); SymbolRegistry::AddPtr p = registry.lookupForAdd(atom); if (p) return *p; AutoCompartment ac(cx, cx->atomsCompartment(lock), &lock); Symbol* sym = newInternal(cx, SymbolCode::InSymbolRegistry, atom->hash(), atom, lock); if (!sym) return nullptr; // p is still valid here because we have held the lock since the // lookupForAdd call, and newInternal can't GC. if (!registry.add(p, sym)) { // SystemAllocPolicy does not report OOM. ReportOutOfMemory(cx); return nullptr; } return sym; } #ifdef DEBUG void Symbol::dump(FILE* fp) { if (isWellKnownSymbol()) { // All the well-known symbol names are ASCII. description_->dumpCharsNoNewline(fp); } else if (code_ == SymbolCode::InSymbolRegistry || code_ == SymbolCode::UniqueSymbol) { fputs(code_ == SymbolCode::InSymbolRegistry ? "Symbol.for(" : "Symbol(", fp); if (description_) description_->dumpCharsNoNewline(fp); else fputs("undefined", fp); fputc(')', fp); if (code_ == SymbolCode::UniqueSymbol) fprintf(fp, "@%p", (void*) this); } else { fprintf(fp, "", unsigned(code_)); } } #endif // DEBUG bool js::SymbolDescriptiveString(JSContext* cx, Symbol* sym, MutableHandleValue result) { // steps 2-5 StringBuffer sb(cx); if (!sb.append("Symbol(")) return false; RootedString str(cx, sym->description()); if (str) { if (!sb.append(str)) return false; } if (!sb.append(')')) return false; // step 6 str = sb.finishString(); if (!str) return false; result.setString(str); return true; } bool js::IsSymbolOrSymbolWrapper(const Value& v) { return v.isSymbol() || (v.isObject() && v.toObject().is()); } JS::Symbol* js::ToSymbolPrimitive(const Value& v) { MOZ_ASSERT(IsSymbolOrSymbolWrapper(v)); return v.isSymbol() ? v.toSymbol() : v.toObject().as().unbox(); } JS::ubi::Node::Size JS::ubi::Concrete::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()); }