1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/SymbolType.h"
8
9 #include "builtin/Symbol.h"
10 #include "gc/Allocator.h"
11 #include "gc/HashUtil.h"
12 #include "gc/Rooting.h"
13 #include "util/StringBuffer.h"
14 #include "vm/JSContext.h"
15 #include "vm/Realm.h"
16
17 #include "vm/Realm-inl.h"
18
19 using JS::Symbol;
20 using namespace js;
21
newInternal(JSContext * cx,JS::SymbolCode code,uint32_t hash,HandleAtom description)22 Symbol* Symbol::newInternal(JSContext* cx, JS::SymbolCode code, uint32_t hash,
23 HandleAtom description) {
24 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
25 AutoAllocInAtomsZone az(cx);
26
27 Symbol* p = Allocate<JS::Symbol>(cx);
28 if (!p) {
29 return nullptr;
30 }
31 return new (p) Symbol(code, hash, description);
32 }
33
new_(JSContext * cx,JS::SymbolCode code,HandleString description)34 Symbol* Symbol::new_(JSContext* cx, JS::SymbolCode code,
35 HandleString description) {
36 RootedAtom atom(cx);
37 if (description) {
38 atom = AtomizeString(cx, description);
39 if (!atom) {
40 return nullptr;
41 }
42 }
43
44 Symbol* sym = newInternal(cx, code, cx->runtime()->randomHashCode(), atom);
45 if (sym) {
46 cx->markAtom(sym);
47 }
48 return sym;
49 }
50
for_(JSContext * cx,HandleString description)51 Symbol* Symbol::for_(JSContext* cx, HandleString description) {
52 RootedAtom atom(cx, AtomizeString(cx, description));
53 if (!atom) {
54 return nullptr;
55 }
56
57 SymbolRegistry& registry = cx->symbolRegistry();
58 DependentAddPtr<SymbolRegistry> p(cx, registry, atom);
59 if (p) {
60 cx->markAtom(*p);
61 return *p;
62 }
63
64 // Rehash the hash of the atom to give the corresponding symbol a hash
65 // that is different than the hash of the corresponding atom.
66 HashNumber hash = mozilla::HashGeneric(atom->hash());
67 Symbol* sym = newInternal(cx, SymbolCode::InSymbolRegistry, hash, atom);
68 if (!sym) {
69 return nullptr;
70 }
71
72 if (!p.add(cx, registry, atom, sym)) {
73 return nullptr;
74 }
75
76 cx->markAtom(sym);
77 return sym;
78 }
79
80 #if defined(DEBUG) || defined(JS_JITSPEW)
dump()81 void Symbol::dump() {
82 js::Fprinter out(stderr);
83 dump(out);
84 }
85
dump(js::GenericPrinter & out)86 void Symbol::dump(js::GenericPrinter& out) {
87 if (isWellKnownSymbol()) {
88 // All the well-known symbol names are ASCII.
89 description()->dumpCharsNoNewline(out);
90 } else if (code_ == SymbolCode::InSymbolRegistry ||
91 code_ == SymbolCode::UniqueSymbol) {
92 out.printf(code_ == SymbolCode::InSymbolRegistry ? "Symbol.for("
93 : "Symbol(");
94
95 if (description()) {
96 description()->dumpCharsNoNewline(out);
97 } else {
98 out.printf("undefined");
99 }
100
101 out.putChar(')');
102
103 if (code_ == SymbolCode::UniqueSymbol) {
104 out.printf("@%p", (void*)this);
105 }
106 } else if (code_ == SymbolCode::PrivateNameSymbol) {
107 MOZ_ASSERT(description());
108 out.putChar('#');
109 description()->dumpCharsNoNewline(out);
110 out.printf("@%p", (void*)this);
111 } else {
112 out.printf("<Invalid Symbol code=%u>", unsigned(code_));
113 }
114 }
115 #endif // defined(DEBUG) || defined(JS_JITSPEW)
116
SymbolDescriptiveString(JSContext * cx,Symbol * sym,MutableHandleValue result)117 bool js::SymbolDescriptiveString(JSContext* cx, Symbol* sym,
118 MutableHandleValue result) {
119 // steps 2-5
120 JSStringBuilder sb(cx);
121 if (!sb.append("Symbol(")) {
122 return false;
123 }
124 if (JSAtom* desc = sym->description()) {
125 if (!sb.append(desc)) {
126 return false;
127 }
128 }
129 if (!sb.append(')')) {
130 return false;
131 }
132
133 // step 6
134 JSString* str = sb.finishString();
135 if (!str) {
136 return false;
137 }
138 result.setString(str);
139 return true;
140 }
141
size(mozilla::MallocSizeOf mallocSizeOf) const142 JS::ubi::Node::Size JS::ubi::Concrete<JS::Symbol>::size(
143 mozilla::MallocSizeOf mallocSizeOf) const {
144 // If we start allocating symbols in the nursery, we will need to update
145 // this method.
146 MOZ_ASSERT(get().isTenured());
147 return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
148 }
149