SymbolType.cpp (5793B)
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 "gc/HashUtil.h" 10 #include "js/Printer.h" // js::GenericPrinter, js::Fprinter 11 #include "util/StringBuilder.h" 12 #include "vm/JSContext.h" 13 #include "vm/JSONPrinter.h" // js::JSONPrinter 14 #include "vm/Realm.h" 15 16 #include "vm/Realm-inl.h" 17 18 using JS::Symbol; 19 using namespace js; 20 21 Symbol* Symbol::newInternal(JSContext* cx, JS::SymbolCode code, uint32_t hash, 22 Handle<JSAtom*> description) { 23 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime())); 24 AutoAllocInAtomsZone az(cx); 25 return cx->newCell<Symbol>(code, hash, description); 26 } 27 28 Symbol* Symbol::new_(JSContext* cx, JS::SymbolCode code, 29 HandleString description) { 30 Rooted<JSAtom*> atom(cx); 31 if (description) { 32 atom = AtomizeString(cx, description); 33 if (!atom) { 34 return nullptr; 35 } 36 } 37 38 Symbol* sym = newInternal(cx, code, cx->runtime()->randomHashCode(), atom); 39 if (sym) { 40 cx->markAtom(sym); 41 } 42 return sym; 43 } 44 45 Symbol* Symbol::newWellKnown(JSContext* cx, JS::SymbolCode code, 46 Handle<PropertyName*> description) { 47 return newInternal(cx, code, cx->runtime()->randomHashCode(), description); 48 } 49 50 Symbol* Symbol::for_(JSContext* cx, HandleString description) { 51 Rooted<JSAtom*> atom(cx, AtomizeString(cx, description)); 52 if (!atom) { 53 return nullptr; 54 } 55 56 SymbolRegistry& registry = cx->symbolRegistry(); 57 DependentAddPtr<SymbolRegistry> p(cx, registry, atom); 58 if (p) { 59 cx->markAtom(*p); 60 return *p; 61 } 62 63 // Rehash the hash of the atom to give the corresponding symbol a hash 64 // that is different than the hash of the corresponding atom. 65 HashNumber hash = mozilla::HashGeneric(atom->hash()); 66 Symbol* sym = newInternal(cx, SymbolCode::InSymbolRegistry, hash, atom); 67 if (!sym) { 68 return nullptr; 69 } 70 71 if (!p.add(cx, registry, atom, sym)) { 72 return nullptr; 73 } 74 75 cx->markAtom(sym); 76 return sym; 77 } 78 79 #if defined(DEBUG) || defined(JS_JITSPEW) 80 void Symbol::dump() const { 81 js::Fprinter out(stderr); 82 dump(out); 83 } 84 85 void Symbol::dump(js::GenericPrinter& out) const { 86 js::JSONPrinter json(out); 87 dump(json); 88 out.put("\n"); 89 } 90 91 void Symbol::dump(js::JSONPrinter& json) const { 92 json.beginObject(); 93 dumpFields(json); 94 json.endObject(); 95 } 96 97 template <typename KnownF, typename UnknownF> 98 void SymbolCodeToString(JS::SymbolCode code, KnownF known, UnknownF unknown) { 99 switch (code) { 100 # define DEFINE_CASE(name) \ 101 case JS::SymbolCode::name: \ 102 known(#name); \ 103 break; 104 JS_FOR_EACH_WELL_KNOWN_SYMBOL(DEFINE_CASE) 105 # undef DEFINE_CASE 106 107 case JS::SymbolCode::Limit: 108 known("Limit"); 109 break; 110 case JS::SymbolCode::WellKnownAPILimit: 111 known("WellKnownAPILimit"); 112 break; 113 case JS::SymbolCode::PrivateNameSymbol: 114 known("PrivateNameSymbol"); 115 break; 116 case JS::SymbolCode::InSymbolRegistry: 117 known("InSymbolRegistry"); 118 break; 119 case JS::SymbolCode::UniqueSymbol: 120 known("UniqueSymbol"); 121 break; 122 default: 123 unknown(uint32_t(code)); 124 break; 125 } 126 } 127 128 void Symbol::dumpFields(js::JSONPrinter& json) const { 129 json.formatProperty("address", "(JS::Symbol*)0x%p", this); 130 131 SymbolCodeToString( 132 code_, [&](const char* name) { json.property("code", name); }, 133 [&](uint32_t code) { 134 json.formatProperty("code", "Unknown(%08x)", code); 135 }); 136 137 json.formatProperty("hash", "0x%08x", hash()); 138 139 if (description()) { 140 js::GenericPrinter& out = json.beginStringProperty("description"); 141 description()->dumpCharsNoQuote(out); 142 json.endStringProperty(); 143 } else { 144 json.nullProperty("description"); 145 } 146 } 147 148 void Symbol::dumpStringContent(js::GenericPrinter& out) const { 149 dumpPropertyName(out); 150 151 if (!isWellKnownSymbol()) { 152 out.printf(" @ (JS::Symbol*)0x%p", this); 153 } 154 } 155 156 void Symbol::dumpPropertyName(js::GenericPrinter& out) const { 157 if (isWellKnownSymbol()) { 158 // All the well-known symbol names are ASCII. 159 description()->dumpCharsNoQuote(out); 160 } else if (code_ == SymbolCode::InSymbolRegistry || 161 code_ == SymbolCode::UniqueSymbol) { 162 out.printf(code_ == SymbolCode::InSymbolRegistry ? "Symbol.for(" 163 : "Symbol("); 164 165 if (description()) { 166 description()->dumpCharsSingleQuote(out); 167 } else { 168 out.printf("undefined"); 169 } 170 171 out.putChar(')'); 172 } else if (code_ == SymbolCode::PrivateNameSymbol) { 173 MOZ_ASSERT(description()); 174 out.putChar('#'); 175 description()->dumpCharsNoQuote(out); 176 } else { 177 out.printf("<Invalid Symbol code=%u>", unsigned(code_)); 178 } 179 } 180 #endif // defined(DEBUG) || defined(JS_JITSPEW) 181 182 bool js::SymbolDescriptiveString(JSContext* cx, Symbol* sym, 183 MutableHandleValue result) { 184 // steps 2-5 185 JSStringBuilder sb(cx); 186 if (!sb.append("Symbol(")) { 187 return false; 188 } 189 if (JSAtom* desc = sym->description()) { 190 if (!sb.append(desc)) { 191 return false; 192 } 193 } 194 if (!sb.append(')')) { 195 return false; 196 } 197 198 // step 6 199 JSString* str = sb.finishString(); 200 if (!str) { 201 return false; 202 } 203 result.setString(str); 204 return true; 205 } 206 207 JS::ubi::Node::Size JS::ubi::Concrete<JS::Symbol>::size( 208 mozilla::MallocSizeOf mallocSizeOf) const { 209 // If we start allocating symbols in the nursery, we will need to update 210 // this method. 211 MOZ_ASSERT(get().isTenured()); 212 return js::gc::Arena::thingSize(get().asTenured().getAllocKind()); 213 }