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 jsatom_h
8 #define jsatom_h
9 
10 #include "mozilla/HashFunctions.h"
11 
12 #include "jsalloc.h"
13 
14 #include "gc/Barrier.h"
15 #include "gc/Marking.h"
16 #include "gc/Rooting.h"
17 #include "js/GCAPI.h"
18 #include "js/GCHashTable.h"
19 #include "vm/CommonPropertyNames.h"
20 
21 class JSAtom;
22 class JSAutoByteString;
23 
24 namespace js {
25 
26 /*
27  * Return a printable, lossless char[] representation of a string-type atom.
28  * The lifetime of the result matches the lifetime of bytes.
29  */
30 extern const char*
31 AtomToPrintableString(ExclusiveContext* cx, JSAtom* atom, JSAutoByteString* bytes);
32 
33 class AtomStateEntry
34 {
35     uintptr_t bits;
36 
37     static const uintptr_t NO_TAG_MASK = uintptr_t(-1) - 1;
38 
39   public:
AtomStateEntry()40     AtomStateEntry() : bits(0) {}
AtomStateEntry(const AtomStateEntry & other)41     AtomStateEntry(const AtomStateEntry& other) : bits(other.bits) {}
AtomStateEntry(JSAtom * ptr,bool tagged)42     AtomStateEntry(JSAtom* ptr, bool tagged)
43       : bits(uintptr_t(ptr) | uintptr_t(tagged))
44     {
45         MOZ_ASSERT((uintptr_t(ptr) & 0x1) == 0);
46     }
47 
isPinned()48     bool isPinned() const {
49         return bits & 0x1;
50     }
51 
52     /*
53      * Non-branching code sequence. Note that the const_cast is safe because
54      * the hash function doesn't consider the tag to be a portion of the key.
55      */
setPinned(bool pinned)56     void setPinned(bool pinned) const {
57         const_cast<AtomStateEntry*>(this)->bits |= uintptr_t(pinned);
58     }
59 
60     JSAtom* asPtr() const;
61     JSAtom* asPtrUnbarriered() const;
62 
needsSweep()63     bool needsSweep() {
64         JSAtom* atom = asPtrUnbarriered();
65         return gc::IsAboutToBeFinalizedUnbarriered(&atom);
66     }
67 };
68 
69 struct AtomHasher
70 {
71     struct Lookup
72     {
73         union {
74             const JS::Latin1Char* latin1Chars;
75             const char16_t* twoByteChars;
76         };
77         bool isLatin1;
78         size_t length;
79         const JSAtom* atom; /* Optional. */
80         JS::AutoCheckCannotGC nogc;
81 
82         HashNumber hash;
83 
LookupAtomHasher::Lookup84         Lookup(const char16_t* chars, size_t length)
85           : twoByteChars(chars), isLatin1(false), length(length), atom(nullptr)
86         {
87             hash = mozilla::HashString(chars, length);
88         }
LookupAtomHasher::Lookup89         Lookup(const JS::Latin1Char* chars, size_t length)
90           : latin1Chars(chars), isLatin1(true), length(length), atom(nullptr)
91         {
92             hash = mozilla::HashString(chars, length);
93         }
94         inline explicit Lookup(const JSAtom* atom);
95     };
96 
hashAtomHasher97     static HashNumber hash(const Lookup& l) { return l.hash; }
98     static inline bool match(const AtomStateEntry& entry, const Lookup& lookup);
rekeyAtomHasher99     static void rekey(AtomStateEntry& k, const AtomStateEntry& newKey) { k = newKey; }
100 };
101 
102 using AtomSet = js::GCHashSet<AtomStateEntry, AtomHasher, SystemAllocPolicy>;
103 
104 // This class is a wrapper for AtomSet that is used to ensure the AtomSet is
105 // not modified. It should only expose read-only methods from AtomSet.
106 // Note however that the atoms within the table can be marked during GC.
107 class FrozenAtomSet
108 {
109     AtomSet* mSet;
110 
111 public:
112     // This constructor takes ownership of the passed-in AtomSet.
FrozenAtomSet(AtomSet * set)113     explicit FrozenAtomSet(AtomSet* set) { mSet = set; }
114 
~FrozenAtomSet()115     ~FrozenAtomSet() { js_delete(mSet); }
116 
117     AtomSet::Ptr readonlyThreadsafeLookup(const AtomSet::Lookup& l) const;
118 
sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)119     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
120         return mSet->sizeOfIncludingThis(mallocSizeOf);
121     }
122 
123     typedef AtomSet::Range Range;
124 
all()125     AtomSet::Range all() const { return mSet->all(); }
126 };
127 
128 class PropertyName;
129 
130 }  /* namespace js */
131 
132 extern bool
133 AtomIsPinned(JSContext* cx, JSAtom* atom);
134 
135 /* Well-known predefined C strings. */
136 #define DECLARE_PROTO_STR(name,code,init,clasp) extern const char js_##name##_str[];
137 JS_FOR_EACH_PROTOTYPE(DECLARE_PROTO_STR)
138 #undef DECLARE_PROTO_STR
139 
140 #define DECLARE_CONST_CHAR_STR(idpart, id, text)  extern const char js_##idpart##_str[];
141 FOR_EACH_COMMON_PROPERTYNAME(DECLARE_CONST_CHAR_STR)
142 #undef DECLARE_CONST_CHAR_STR
143 
144 /* Constant strings that are not atomized. */
145 extern const char js_break_str[];
146 extern const char js_case_str[];
147 extern const char js_catch_str[];
148 extern const char js_class_str[];
149 extern const char js_close_str[];
150 extern const char js_const_str[];
151 extern const char js_continue_str[];
152 extern const char js_debugger_str[];
153 extern const char js_default_str[];
154 extern const char js_do_str[];
155 extern const char js_else_str[];
156 extern const char js_enum_str[];
157 extern const char js_export_str[];
158 extern const char js_extends_str[];
159 extern const char js_finally_str[];
160 extern const char js_for_str[];
161 extern const char js_getter_str[];
162 extern const char js_if_str[];
163 extern const char js_implements_str[];
164 extern const char js_import_str[];
165 extern const char js_in_str[];
166 extern const char js_instanceof_str[];
167 extern const char js_interface_str[];
168 extern const char js_package_str[];
169 extern const char js_private_str[];
170 extern const char js_protected_str[];
171 extern const char js_public_str[];
172 extern const char js_send_str[];
173 extern const char js_setter_str[];
174 extern const char js_static_str[];
175 extern const char js_super_str[];
176 extern const char js_switch_str[];
177 extern const char js_this_str[];
178 extern const char js_try_str[];
179 extern const char js_typeof_str[];
180 extern const char js_void_str[];
181 extern const char js_while_str[];
182 extern const char js_with_str[];
183 
184 namespace js {
185 
186 /*
187  * Atom tracing and garbage collection hooks.
188  */
189 void
190 MarkAtoms(JSTracer* trc);
191 
192 void
193 MarkPermanentAtoms(JSTracer* trc);
194 
195 void
196 MarkWellKnownSymbols(JSTracer* trc);
197 
198 /* N.B. must correspond to boolean tagging behavior. */
199 enum PinningBehavior
200 {
201     DoNotPinAtom = false,
202     PinAtom = true
203 };
204 
205 extern JSAtom*
206 Atomize(ExclusiveContext* cx, const char* bytes, size_t length,
207         js::PinningBehavior pin = js::DoNotPinAtom);
208 
209 template <typename CharT>
210 extern JSAtom*
211 AtomizeChars(ExclusiveContext* cx, const CharT* chars, size_t length,
212              js::PinningBehavior pin = js::DoNotPinAtom);
213 
214 extern JSAtom*
215 AtomizeString(ExclusiveContext* cx, JSString* str, js::PinningBehavior pin = js::DoNotPinAtom);
216 
217 template <AllowGC allowGC>
218 extern JSAtom*
219 ToAtom(ExclusiveContext* cx, typename MaybeRooted<Value, allowGC>::HandleType v);
220 
221 enum XDRMode {
222     XDR_ENCODE,
223     XDR_DECODE
224 };
225 
226 template <XDRMode mode>
227 class XDRState;
228 
229 template<XDRMode mode>
230 bool
231 XDRAtom(XDRState<mode>* xdr, js::MutableHandleAtom atomp);
232 
233 } /* namespace js */
234 
235 #endif /* jsatom_h */
236