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 : #ifndef vm_Symbol_h
8 : #define vm_Symbol_h
9 :
10 : #include "mozilla/Attributes.h"
11 :
12 : #include <stdio.h>
13 :
14 : #include "jsalloc.h"
15 : #include "jsapi.h"
16 :
17 : #include "gc/Barrier.h"
18 : #include "gc/Marking.h"
19 : #include "js/GCHashTable.h"
20 : #include "js/RootingAPI.h"
21 : #include "js/TypeDecls.h"
22 : #include "js/Utility.h"
23 : #include "vm/String.h"
24 :
25 : namespace js {
26 : class AutoLockForExclusiveAccess;
27 : } // namespace js
28 :
29 : namespace JS {
30 :
31 : class Symbol : public js::gc::TenuredCell
32 : {
33 : private:
34 : SymbolCode code_;
35 :
36 : // Each Symbol gets its own hash code so that we don't have to use
37 : // addresses as hash codes (a security hazard).
38 : js::HashNumber hash_;
39 :
40 : JSAtom* description_;
41 :
42 : // The minimum allocation size is sizeof(JSString): 16 bytes on 32-bit
43 : // architectures and 24 bytes on 64-bit. A size_t of padding makes Symbol
44 : // the minimum size on both.
45 : size_t unused_;
46 :
47 56 : Symbol(SymbolCode code, js::HashNumber hash, JSAtom* desc)
48 56 : : code_(code), hash_(hash), description_(desc)
49 : {
50 : // Silence warnings about unused_ being... unused.
51 : (void)unused_;
52 56 : }
53 :
54 : Symbol(const Symbol&) = delete;
55 : void operator=(const Symbol&) = delete;
56 :
57 : static Symbol*
58 : newInternal(JSContext* cx, SymbolCode code, js::HashNumber hash,
59 : JSAtom* description, js::AutoLockForExclusiveAccess& lock);
60 :
61 : public:
62 : static Symbol* new_(JSContext* cx, SymbolCode code, JSString* description);
63 : static Symbol* for_(JSContext* cx, js::HandleString description);
64 :
65 2335 : JSAtom* description() const { return description_; }
66 86 : SymbolCode code() const { return code_; }
67 8768 : js::HashNumber hash() const { return hash_; }
68 :
69 6164 : bool isWellKnownSymbol() const { return uint32_t(code_) < WellKnownSymbolLimit; }
70 :
71 : // An "interesting symbol" is a well-known symbol, like @@toStringTag,
72 : // that's often looked up on random objects but is usually not present. We
73 : // optimize this by setting a flag on the object's BaseShape when such
74 : // symbol properties are added, so we can optimize lookups on objects that
75 : // don't have the BaseShape flag.
76 4350 : bool isInterestingSymbol() const {
77 4350 : return code_ == SymbolCode::toStringTag || code_ == SymbolCode::toPrimitive;
78 : }
79 :
80 : static const JS::TraceKind TraceKind = JS::TraceKind::Symbol;
81 0 : inline void traceChildren(JSTracer* trc) {
82 0 : if (description_)
83 0 : js::TraceManuallyBarrieredEdge(trc, &description_, "description");
84 0 : }
85 0 : inline void finalize(js::FreeOp*) {}
86 :
87 0 : static MOZ_ALWAYS_INLINE void writeBarrierPre(Symbol* thing) {
88 0 : if (thing && !thing->isWellKnownSymbol())
89 0 : thing->asTenured().writeBarrierPre(thing);
90 0 : }
91 :
92 : size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
93 : return mallocSizeOf(this);
94 : }
95 :
96 : #ifdef DEBUG
97 : void dump(FILE* fp = stderr);
98 : #endif
99 : };
100 :
101 : } /* namespace JS */
102 :
103 : namespace js {
104 :
105 : /* Hash policy used by the SymbolRegistry. */
106 : struct HashSymbolsByDescription
107 : {
108 : typedef JS::Symbol* Key;
109 : typedef JSAtom* Lookup;
110 :
111 0 : static HashNumber hash(Lookup l) {
112 0 : return HashNumber(l->hash());
113 : }
114 0 : static bool match(Key sym, Lookup l) {
115 0 : return sym->description() == l;
116 : }
117 : };
118 :
119 : /*
120 : * The runtime-wide symbol registry, used to implement Symbol.for().
121 : *
122 : * ES6 draft rev 25 (2014 May 22) calls this the GlobalSymbolRegistry List. In
123 : * our implementation, it is not global. There is one per JSRuntime. The
124 : * symbols in the symbol registry, like all symbols, are allocated in the atoms
125 : * compartment and can be directly referenced from any compartment. They are
126 : * never shared across runtimes.
127 : *
128 : * The memory management strategy here is modeled after js::AtomSet. It's like
129 : * a WeakSet. The registry itself does not keep any symbols alive; when a
130 : * symbol in the registry is collected, the registry entry is removed. No GC
131 : * nondeterminism is exposed to scripts, because there is no API for
132 : * enumerating the symbol registry, querying its size, etc.
133 : */
134 0 : class SymbolRegistry : public GCHashSet<ReadBarrieredSymbol,
135 : HashSymbolsByDescription,
136 : SystemAllocPolicy>
137 : {
138 : public:
139 4 : SymbolRegistry() {}
140 : };
141 :
142 : } /* namespace js */
143 :
144 : namespace js {
145 :
146 : // ES6 rev 27 (2014 Aug 24) 19.4.3.3
147 : bool
148 : SymbolDescriptiveString(JSContext* cx, JS::Symbol* sym, JS::MutableHandleValue result);
149 :
150 : bool
151 : IsSymbolOrSymbolWrapper(const JS::Value& v);
152 :
153 : JS::Symbol*
154 : ToSymbolPrimitive(const JS::Value& v);
155 :
156 : } /* namespace js */
157 :
158 : #endif /* vm_Symbol_h */
|