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/. */
7 #ifndef vm_SymbolType_h
8 #define vm_SymbolType_h
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"
23 class JS_PUBLIC_API GenericPrinter
;
29 : public js::gc::CellWithTenuredGCPointer
<js::gc::TenuredCell
, JSAtom
> {
30 friend class js::gc::CellAllocator
;
33 // User description of symbol, stored in the cell header.
34 JSAtom
* description() const { return headerPtr(); }
39 // Each Symbol gets its own hash code so that we don't have to use
40 // addresses as hash codes (a security hazard).
43 Symbol(SymbolCode code
, js::HashNumber hash
, Handle
<JSAtom
*> desc
)
44 : CellWithTenuredGCPointer(desc
), code_(code
), hash_(hash
) {}
46 Symbol(const Symbol
&) = delete;
47 void operator=(const Symbol
&) = delete;
49 static Symbol
* newInternal(JSContext
* cx
, SymbolCode code
,
50 js::HashNumber hash
, Handle
<JSAtom
*> description
);
52 static void staticAsserts() {
53 static_assert(uint32_t(SymbolCode::WellKnownAPILimit
) ==
54 JS::shadow::Symbol::WellKnownAPILimit
,
55 "JS::shadow::Symbol::WellKnownAPILimit must match "
56 "SymbolCode::WellKnownAPILimit");
58 offsetof(Symbol
, code_
) == offsetof(JS::shadow::Symbol
, code_
),
59 "JS::shadow::Symbol::code_ offset must match SymbolCode::code_");
63 static Symbol
* new_(JSContext
* cx
, SymbolCode code
,
64 js::HandleString description
);
65 static Symbol
* newWellKnown(JSContext
* cx
, SymbolCode code
,
66 Handle
<js::PropertyName
*> description
);
67 static Symbol
* for_(JSContext
* cx
, js::HandleString description
);
69 SymbolCode
code() const { return code_
; }
70 js::HashNumber
hash() const { return hash_
; }
72 bool isWellKnownSymbol() const {
73 return uint32_t(code_
) < WellKnownSymbolLimit
;
76 // An "interesting symbol" is a well-known symbol, like @@toStringTag,
77 // that's often looked up on random objects but is usually not present. We
78 // optimize this by setting a flag on the object's BaseShape when such
79 // symbol properties are added, so we can optimize lookups on objects that
80 // don't have the BaseShape flag.
81 bool isInterestingSymbol() const {
82 return code_
== SymbolCode::toStringTag
||
83 code_
== SymbolCode::toPrimitive
||
84 code_
== SymbolCode::isConcatSpreadable
;
87 // Symbol created for the #PrivateName syntax.
88 bool isPrivateName() const { return code_
== SymbolCode::PrivateNameSymbol
; }
90 static const JS::TraceKind TraceKind
= JS::TraceKind::Symbol
;
92 void traceChildren(JSTracer
* trc
);
93 void finalize(JS::GCContext
* gcx
) {}
95 // Override base class implementation to tell GC about well-known symbols.
96 bool isPermanentAndMayBeShared() const { return isWellKnownSymbol(); }
98 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
99 return mallocSizeOf(this);
102 #if defined(DEBUG) || defined(JS_JITSPEW)
103 void dump(); // Debugger-friendly stderr dump.
104 void dump(js::GenericPrinter
& out
);
107 static constexpr size_t offsetOfHash() { return offsetof(Symbol
, hash_
); }
114 /* Hash policy used by the SymbolRegistry. */
115 struct HashSymbolsByDescription
{
116 using Key
= JS::Symbol
*;
117 using Lookup
= JSAtom
*;
119 static HashNumber
hash(Lookup l
) { return HashNumber(l
->hash()); }
120 static bool match(Key sym
, Lookup l
) { return sym
->description() == l
; }
124 * [SMDOC] Symbol.for() registry (ES6 GlobalSymbolRegistry)
126 * The runtime-wide symbol registry, used to implement Symbol.for().
128 * ES6 draft rev 25 (2014 May 22) calls this the GlobalSymbolRegistry List. In
129 * our implementation, it is not global. There is one per JSRuntime. The
130 * symbols in the symbol registry, like all symbols, are allocated in the atoms
131 * compartment and can be directly referenced from any compartment. They are
132 * never shared across runtimes.
134 * The memory management strategy here is modeled after js::AtomSet. It's like
135 * a WeakSet. The registry itself does not keep any symbols alive; when a
136 * symbol in the registry is collected, the registry entry is removed. No GC
137 * nondeterminism is exposed to scripts, because there is no API for
138 * enumerating the symbol registry, querying its size, etc.
141 : public GCHashSet
<WeakHeapPtr
<JS::Symbol
*>, HashSymbolsByDescription
,
144 SymbolRegistry() = default;
147 // ES6 rev 27 (2014 Aug 24) 19.4.3.3
148 bool SymbolDescriptiveString(JSContext
* cx
, JS::Symbol
* sym
,
149 JS::MutableHandleValue result
);
153 #endif /* vm_SymbolType_h */