diff options
Diffstat (limited to 'js/src/vm/Symbol.cpp')
-rw-r--r-- | js/src/vm/Symbol.cpp | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/js/src/vm/Symbol.cpp b/js/src/vm/Symbol.cpp new file mode 100644 index 000000000..59903c38a --- /dev/null +++ b/js/src/vm/Symbol.cpp @@ -0,0 +1,152 @@ +/* -*- 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<JS::Symbol, NoGC>(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, "<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(const Value& v) +{ + return v.isSymbol() || (v.isObject() && v.toObject().is<SymbolObject>()); +} + +JS::Symbol* +js::ToSymbolPrimitive(const 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()); +} |