Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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/Symbol.h"
8 :
9 : #include "jscntxt.h"
10 : #include "jscompartment.h"
11 :
12 : #include "builtin/SymbolObject.h"
13 : #include "gc/Allocator.h"
14 : #include "gc/Rooting.h"
15 : #include "vm/StringBuffer.h"
16 :
17 : #include "jscompartmentinlines.h"
18 :
19 : using JS::Symbol;
20 : using namespace js;
21 :
22 : Symbol*
23 56 : Symbol::newInternal(JSContext* cx, JS::SymbolCode code, uint32_t hash, JSAtom* description,
24 : AutoLockForExclusiveAccess& lock)
25 : {
26 56 : MOZ_ASSERT(cx->compartment() == cx->atomsCompartment(lock));
27 :
28 : // Following js::AtomizeString, we grudgingly forgo last-ditch GC here.
29 56 : Symbol* p = Allocate<JS::Symbol, NoGC>(cx);
30 56 : if (!p) {
31 0 : ReportOutOfMemory(cx);
32 0 : return nullptr;
33 : }
34 56 : return new (p) Symbol(code, hash, description);
35 : }
36 :
37 : Symbol*
38 56 : Symbol::new_(JSContext* cx, JS::SymbolCode code, JSString* description)
39 : {
40 56 : JSAtom* atom = nullptr;
41 56 : if (description) {
42 56 : atom = AtomizeString(cx, description);
43 56 : if (!atom)
44 0 : return nullptr;
45 : }
46 :
47 : // Lock to allocate. If symbol allocation becomes a bottleneck, this can
48 : // probably be replaced with an assertion that we're on the active thread.
49 112 : AutoLockForExclusiveAccess lock(cx);
50 : Symbol* sym;
51 : {
52 112 : AutoAtomsCompartment ac(cx, lock);
53 56 : sym = newInternal(cx, code, cx->compartment()->randomHashCode(), atom, lock);
54 : }
55 56 : if (sym)
56 56 : cx->markAtom(sym);
57 56 : return sym;
58 : }
59 :
60 : Symbol*
61 0 : Symbol::for_(JSContext* cx, HandleString description)
62 : {
63 0 : JSAtom* atom = AtomizeString(cx, description);
64 0 : if (!atom)
65 0 : return nullptr;
66 :
67 0 : AutoLockForExclusiveAccess lock(cx);
68 :
69 0 : SymbolRegistry& registry = cx->symbolRegistry(lock);
70 0 : SymbolRegistry::AddPtr p = registry.lookupForAdd(atom);
71 0 : if (p) {
72 0 : cx->markAtom(*p);
73 0 : return *p;
74 : }
75 :
76 : Symbol* sym;
77 : {
78 0 : AutoAtomsCompartment ac(cx, lock);
79 0 : sym = newInternal(cx, SymbolCode::InSymbolRegistry, atom->hash(), atom, lock);
80 0 : if (!sym)
81 0 : return nullptr;
82 :
83 : // p is still valid here because we have held the lock since the
84 : // lookupForAdd call, and newInternal can't GC.
85 0 : if (!registry.add(p, sym)) {
86 : // SystemAllocPolicy does not report OOM.
87 0 : ReportOutOfMemory(cx);
88 0 : return nullptr;
89 : }
90 : }
91 0 : cx->markAtom(sym);
92 0 : return sym;
93 : }
94 :
95 : #ifdef DEBUG
96 : void
97 0 : Symbol::dump(FILE* fp)
98 : {
99 0 : if (isWellKnownSymbol()) {
100 : // All the well-known symbol names are ASCII.
101 0 : description_->dumpCharsNoNewline(fp);
102 0 : } else if (code_ == SymbolCode::InSymbolRegistry || code_ == SymbolCode::UniqueSymbol) {
103 0 : fputs(code_ == SymbolCode::InSymbolRegistry ? "Symbol.for(" : "Symbol(", fp);
104 :
105 0 : if (description_)
106 0 : description_->dumpCharsNoNewline(fp);
107 : else
108 0 : fputs("undefined", fp);
109 :
110 0 : fputc(')', fp);
111 :
112 0 : if (code_ == SymbolCode::UniqueSymbol)
113 0 : fprintf(fp, "@%p", (void*) this);
114 : } else {
115 0 : fprintf(fp, "<Invalid Symbol code=%u>", unsigned(code_));
116 : }
117 0 : }
118 : #endif // DEBUG
119 :
120 : bool
121 0 : js::SymbolDescriptiveString(JSContext* cx, Symbol* sym, MutableHandleValue result)
122 : {
123 : // steps 2-5
124 0 : StringBuffer sb(cx);
125 0 : if (!sb.append("Symbol("))
126 0 : return false;
127 0 : RootedString str(cx, sym->description());
128 0 : if (str) {
129 0 : if (!sb.append(str))
130 0 : return false;
131 : }
132 0 : if (!sb.append(')'))
133 0 : return false;
134 :
135 : // step 6
136 0 : str = sb.finishString();
137 0 : if (!str)
138 0 : return false;
139 0 : result.setString(str);
140 0 : return true;
141 : }
142 :
143 : bool
144 2513 : js::IsSymbolOrSymbolWrapper(const Value& v)
145 : {
146 2513 : return v.isSymbol() || (v.isObject() && v.toObject().is<SymbolObject>());
147 : }
148 :
149 : JS::Symbol*
150 1252 : js::ToSymbolPrimitive(const Value& v)
151 : {
152 1252 : MOZ_ASSERT(IsSymbolOrSymbolWrapper(v));
153 1252 : return v.isSymbol() ? v.toSymbol() : v.toObject().as<SymbolObject>().unbox();
154 : }
155 :
156 :
157 : JS::ubi::Node::Size
158 0 : JS::ubi::Concrete<JS::Symbol>::size(mozilla::MallocSizeOf mallocSizeOf) const
159 : {
160 : // If we start allocating symbols in the nursery, we will need to update
161 : // this method.
162 0 : MOZ_ASSERT(get().isTenured());
163 0 : return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
164 : }
|