SymbolType.h (5579B)
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 #ifndef vm_SymbolType_h 8 #define vm_SymbolType_h 9 10 #include <stdio.h> 11 12 #include "gc/Barrier.h" 13 #include "gc/Tracer.h" 14 #include "js/AllocPolicy.h" 15 #include "js/GCHashTable.h" 16 #include "js/RootingAPI.h" 17 #include "js/shadow/Symbol.h" // JS::shadow::Symbol 18 #include "js/Symbol.h" 19 #include "js/TypeDecls.h" 20 #include "vm/StringType.h" 21 22 namespace js { 23 class JS_PUBLIC_API GenericPrinter; 24 class JSONPrinter; 25 } /* namespace js */ 26 27 namespace JS { 28 29 class Symbol 30 : public js::gc::CellWithTenuredGCPointer<js::gc::TenuredCell, JSAtom> { 31 friend class js::gc::CellAllocator; 32 33 public: 34 // User description of symbol, stored in the cell header. 35 JSAtom* description() const { return headerPtr(); } 36 37 private: 38 SymbolCode code_; 39 40 // Each Symbol gets its own hash code so that we don't have to use 41 // addresses as hash codes (a security hazard). 42 js::HashNumber hash_; 43 44 Symbol(SymbolCode code, js::HashNumber hash, Handle<JSAtom*> desc) 45 : CellWithTenuredGCPointer(desc), code_(code), hash_(hash) {} 46 47 Symbol(const Symbol&) = delete; 48 void operator=(const Symbol&) = delete; 49 50 static Symbol* newInternal(JSContext* cx, SymbolCode code, 51 js::HashNumber hash, Handle<JSAtom*> description); 52 53 static void staticAsserts() { 54 static_assert(uint32_t(SymbolCode::WellKnownAPILimit) == 55 JS::shadow::Symbol::WellKnownAPILimit, 56 "JS::shadow::Symbol::WellKnownAPILimit must match " 57 "SymbolCode::WellKnownAPILimit"); 58 static_assert( 59 offsetof(Symbol, code_) == offsetof(JS::shadow::Symbol, code_), 60 "JS::shadow::Symbol::code_ offset must match SymbolCode::code_"); 61 } 62 63 public: 64 static Symbol* new_(JSContext* cx, SymbolCode code, 65 js::HandleString description); 66 static Symbol* newWellKnown(JSContext* cx, SymbolCode code, 67 Handle<js::PropertyName*> description); 68 static Symbol* for_(JSContext* cx, js::HandleString description); 69 70 SymbolCode code() const { return code_; } 71 js::HashNumber hash() const { return hash_; } 72 73 bool isWellKnownSymbol() const { 74 return uint32_t(code_) < WellKnownSymbolLimit; 75 } 76 77 // An "interesting symbol" is a well-known symbol, like @@toStringTag, 78 // that's often looked up on random objects but is usually not present. We 79 // optimize this by setting a flag on the object's BaseShape when such 80 // symbol properties are added, so we can optimize lookups on objects that 81 // don't have the BaseShape flag. 82 bool isInterestingSymbol() const { 83 return code_ == SymbolCode::toStringTag || 84 code_ == SymbolCode::toPrimitive || 85 code_ == SymbolCode::isConcatSpreadable; 86 } 87 88 // Symbol created for the #PrivateName syntax. 89 bool isPrivateName() const { return code_ == SymbolCode::PrivateNameSymbol; } 90 91 static const JS::TraceKind TraceKind = JS::TraceKind::Symbol; 92 93 void traceChildren(JSTracer* trc); 94 95 // Override base class implementation to tell GC about well-known symbols. 96 bool isPermanentAndMayBeShared() const { return isWellKnownSymbol(); } 97 98 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { 99 return mallocSizeOf(this); 100 } 101 102 #if defined(DEBUG) || defined(JS_JITSPEW) 103 void dump() const; // Debugger-friendly stderr dump. 104 void dump(js::GenericPrinter& out) const; 105 void dump(js::JSONPrinter& json) const; 106 107 void dumpFields(js::JSONPrinter& json) const; 108 void dumpStringContent(js::GenericPrinter& out) const; 109 void dumpPropertyName(js::GenericPrinter& out) const; 110 #endif 111 112 static constexpr size_t offsetOfHash() { return offsetof(Symbol, hash_); } 113 static constexpr size_t offsetOfCode() { return offsetof(Symbol, code_); } 114 }; 115 116 } /* namespace JS */ 117 118 namespace js { 119 120 /* Hash policy used by the SymbolRegistry. */ 121 struct HashSymbolsByDescription { 122 using Key = JS::Symbol*; 123 using Lookup = JSAtom*; 124 125 static HashNumber hash(Lookup l) { return HashNumber(l->hash()); } 126 static bool match(Key sym, Lookup l) { return sym->description() == l; } 127 }; 128 129 /* 130 * [SMDOC] Symbol.for() registry (ES6 GlobalSymbolRegistry) 131 * 132 * The runtime-wide symbol registry, used to implement Symbol.for(). 133 * 134 * ES6 draft rev 25 (2014 May 22) calls this the GlobalSymbolRegistry List. In 135 * our implementation, it is not global. There is one per JSRuntime. The 136 * symbols in the symbol registry, like all symbols, are allocated in the atoms 137 * compartment and can be directly referenced from any compartment. They are 138 * never shared across runtimes. 139 * 140 * The memory management strategy here is modeled after js::AtomSet. It's like 141 * a WeakSet. The registry itself does not keep any symbols alive; when a 142 * symbol in the registry is collected, the registry entry is removed. No GC 143 * nondeterminism is exposed to scripts, because there is no API for 144 * enumerating the symbol registry, querying its size, etc. 145 */ 146 class SymbolRegistry 147 : public GCHashSet<WeakHeapPtr<JS::Symbol*>, HashSymbolsByDescription, 148 SystemAllocPolicy> { 149 public: 150 SymbolRegistry() = default; 151 }; 152 153 // ES6 rev 27 (2014 Aug 24) 19.4.3.3 154 bool SymbolDescriptiveString(JSContext* cx, JS::Symbol* sym, 155 JS::MutableHandleValue result); 156 157 } /* namespace js */ 158 159 #endif /* vm_SymbolType_h */