blob: 4d517e3ad2c1c991122fc31c4eef63ba6a7bb379 [file] [log] [blame]
/* -*- 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"
// Unified leak fix:
#include "builtin/ModuleObject.h"
using JS::Symbol;
using namespace js;
Symbol*
Symbol::newInternal(ExclusiveContext* cx, JS::SymbolCode code, JSAtom* description)
{
MOZ_ASSERT(cx->compartment() == cx->atomsCompartment());
MOZ_ASSERT(cx->atomsCompartment()->runtimeFromAnyThread()->currentThreadHasExclusiveAccess());
// Following js::AtomizeString, we grudgingly forgo last-ditch GC here.
Symbol* p = Allocate<JS::Symbol, NoGC>(cx);
if (!p) {
ReportOutOfMemory(cx);
return nullptr;
}
return new (p) Symbol(code, description);
}
Symbol*
Symbol::new_(ExclusiveContext* cx, JS::SymbolCode code, JSString* description)
{
RootedAtom atom(cx);
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());
return newInternal(cx, code, atom);
}
Symbol*
Symbol::for_(js::ExclusiveContext* cx, HandleString description)
{
JSAtom* atom = AtomizeString(cx, description);
if (!atom)
return nullptr;
AutoLockForExclusiveAccess lock(cx);
SymbolRegistry& registry = cx->symbolRegistry();
SymbolRegistry::AddPtr p = registry.lookupForAdd(atom);
if (p)
return *p;
AutoCompartment ac(cx, cx->atomsCompartment());
Symbol* sym = newInternal(cx, SymbolCode::InSymbolRegistry, atom);
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, "<Invalid Symbol code=%u>", 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(Value v)
{
return v.isSymbol() || (v.isObject() && v.toObject().is<SymbolObject>());
}
JS::Symbol*
js::ToSymbolPrimitive(Value v)
{
MOZ_ASSERT(IsSymbolOrSymbolWrapper(v));
return v.isSymbol() ? v.toSymbol() : v.toObject().as<SymbolObject>().unbox();
}
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());
}