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 jsatominlines_h
8 #define jsatominlines_h
9
10 #include "jsatom.h"
11
12 #include "mozilla/PodOperations.h"
13 #include "mozilla/RangedPtr.h"
14
15 #include "jscntxt.h"
16 #include "jsnum.h"
17
18 #include "vm/String.h"
19
20 inline JSAtom*
asPtr()21 js::AtomStateEntry::asPtr() const
22 {
23 MOZ_ASSERT(bits != 0);
24 JSAtom* atom = reinterpret_cast<JSAtom*>(bits & NO_TAG_MASK);
25 JSString::readBarrier(atom);
26 return atom;
27 }
28
29 inline JSAtom*
asPtrUnbarriered()30 js::AtomStateEntry::asPtrUnbarriered() const
31 {
32 MOZ_ASSERT(bits != 0);
33 return reinterpret_cast<JSAtom*>(bits & NO_TAG_MASK);
34 }
35
36 namespace js {
37
38 inline jsid
AtomToId(JSAtom * atom)39 AtomToId(JSAtom* atom)
40 {
41 JS_STATIC_ASSERT(JSID_INT_MIN == 0);
42
43 uint32_t index;
44 if (atom->isIndex(&index) && index <= JSID_INT_MAX)
45 return INT_TO_JSID(int32_t(index));
46
47 return JSID_FROM_BITS(size_t(atom));
48 }
49
50 inline bool
ValueToIdPure(const Value & v,jsid * id)51 ValueToIdPure(const Value& v, jsid* id)
52 {
53 int32_t i;
54 if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) {
55 *id = INT_TO_JSID(i);
56 return true;
57 }
58
59 if (js::IsSymbolOrSymbolWrapper(v)) {
60 *id = SYMBOL_TO_JSID(js::ToSymbolPrimitive(v));
61 return true;
62 }
63
64 if (!v.isString() || !v.toString()->isAtom())
65 return false;
66
67 *id = AtomToId(&v.toString()->asAtom());
68 return true;
69 }
70
71 template <AllowGC allowGC>
72 inline bool
ValueToId(ExclusiveContext * cx,typename MaybeRooted<Value,allowGC>::HandleType v,typename MaybeRooted<jsid,allowGC>::MutableHandleType idp)73 ValueToId(ExclusiveContext* cx, typename MaybeRooted<Value, allowGC>::HandleType v,
74 typename MaybeRooted<jsid, allowGC>::MutableHandleType idp)
75 {
76 int32_t i;
77 if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) {
78 idp.set(INT_TO_JSID(i));
79 return true;
80 }
81
82 if (js::IsSymbolOrSymbolWrapper(v)) {
83 idp.set(SYMBOL_TO_JSID(js::ToSymbolPrimitive(v)));
84 return true;
85 }
86
87 JSAtom* atom = ToAtom<allowGC>(cx, v);
88 if (!atom)
89 return false;
90
91 idp.set(AtomToId(atom));
92 return true;
93 }
94
95 /*
96 * Write out character representing |index| to the memory just before |end|.
97 * Thus |*end| is not touched, but |end[-1]| and earlier are modified as
98 * appropriate. There must be at least js::UINT32_CHAR_BUFFER_LENGTH elements
99 * before |end| to avoid buffer underflow. The start of the characters written
100 * is returned and is necessarily before |end|.
101 */
102 template <typename T>
103 inline mozilla::RangedPtr<T>
BackfillIndexInCharBuffer(uint32_t index,mozilla::RangedPtr<T> end)104 BackfillIndexInCharBuffer(uint32_t index, mozilla::RangedPtr<T> end)
105 {
106 #ifdef DEBUG
107 /*
108 * Assert that the buffer we're filling will hold as many characters as we
109 * could write out, by dereferencing the index that would hold the most
110 * significant digit.
111 */
112 (void) *(end - UINT32_CHAR_BUFFER_LENGTH);
113 #endif
114
115 do {
116 uint32_t next = index / 10, digit = index % 10;
117 *--end = '0' + digit;
118 index = next;
119 } while (index > 0);
120
121 return end;
122 }
123
124 bool
125 IndexToIdSlow(ExclusiveContext* cx, uint32_t index, MutableHandleId idp);
126
127 inline bool
IndexToId(ExclusiveContext * cx,uint32_t index,MutableHandleId idp)128 IndexToId(ExclusiveContext* cx, uint32_t index, MutableHandleId idp)
129 {
130 if (index <= JSID_INT_MAX) {
131 idp.set(INT_TO_JSID(index));
132 return true;
133 }
134
135 return IndexToIdSlow(cx, index, idp);
136 }
137
138 static MOZ_ALWAYS_INLINE JSFlatString*
IdToString(JSContext * cx,jsid id)139 IdToString(JSContext* cx, jsid id)
140 {
141 if (JSID_IS_STRING(id))
142 return JSID_TO_ATOM(id);
143
144 if (MOZ_LIKELY(JSID_IS_INT(id)))
145 return Int32ToString<CanGC>(cx, JSID_TO_INT(id));
146
147 RootedValue idv(cx, IdToValue(id));
148 JSString* str = ToStringSlow<CanGC>(cx, idv);
149 if (!str)
150 return nullptr;
151
152 return str->ensureFlat(cx);
153 }
154
155 inline
Lookup(const JSAtom * atom)156 AtomHasher::Lookup::Lookup(const JSAtom* atom)
157 : isLatin1(atom->hasLatin1Chars()), length(atom->length()), atom(atom)
158 {
159 hash = atom->hash();
160 if (isLatin1) {
161 latin1Chars = atom->latin1Chars(nogc);
162 MOZ_ASSERT(mozilla::HashString(latin1Chars, length) == hash);
163 } else {
164 twoByteChars = atom->twoByteChars(nogc);
165 MOZ_ASSERT(mozilla::HashString(twoByteChars, length) == hash);
166 }
167 }
168
169 inline bool
match(const AtomStateEntry & entry,const Lookup & lookup)170 AtomHasher::match(const AtomStateEntry& entry, const Lookup& lookup)
171 {
172 JSAtom* key = entry.asPtr();
173 if (lookup.atom)
174 return lookup.atom == key;
175 if (key->length() != lookup.length || key->hash() != lookup.hash)
176 return false;
177
178 if (key->hasLatin1Chars()) {
179 const Latin1Char* keyChars = key->latin1Chars(lookup.nogc);
180 if (lookup.isLatin1)
181 return mozilla::PodEqual(keyChars, lookup.latin1Chars, lookup.length);
182 return EqualChars(keyChars, lookup.twoByteChars, lookup.length);
183 }
184
185 const char16_t* keyChars = key->twoByteChars(lookup.nogc);
186 if (lookup.isLatin1)
187 return EqualChars(lookup.latin1Chars, keyChars, lookup.length);
188 return mozilla::PodEqual(keyChars, lookup.twoByteChars, lookup.length);
189 }
190
191 inline Handle<PropertyName*>
TypeName(JSType type,const JSAtomState & names)192 TypeName(JSType type, const JSAtomState& names)
193 {
194 MOZ_ASSERT(type < JSTYPE_LIMIT);
195 JS_STATIC_ASSERT(offsetof(JSAtomState, undefined) +
196 JSTYPE_LIMIT * sizeof(ImmutablePropertyNamePtr) <=
197 sizeof(JSAtomState));
198 JS_STATIC_ASSERT(JSTYPE_VOID == 0);
199 return (&names.undefined)[type];
200 }
201
202 inline Handle<PropertyName*>
ClassName(JSProtoKey key,JSAtomState & atomState)203 ClassName(JSProtoKey key, JSAtomState& atomState)
204 {
205 MOZ_ASSERT(key < JSProto_LIMIT);
206 JS_STATIC_ASSERT(offsetof(JSAtomState, Null) +
207 JSProto_LIMIT * sizeof(ImmutablePropertyNamePtr) <=
208 sizeof(JSAtomState));
209 JS_STATIC_ASSERT(JSProto_Null == 0);
210 return (&atomState.Null)[key];
211 }
212
213 inline Handle<PropertyName*>
ClassName(JSProtoKey key,JSRuntime * rt)214 ClassName(JSProtoKey key, JSRuntime* rt)
215 {
216 return ClassName(key, *rt->commonNames);
217 }
218
219 inline Handle<PropertyName*>
ClassName(JSProtoKey key,ExclusiveContext * cx)220 ClassName(JSProtoKey key, ExclusiveContext* cx)
221 {
222 return ClassName(key, cx->names());
223 }
224
225 } // namespace js
226
227 #endif /* jsatominlines_h */
228