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_JSAtom_inl_h
8 #define vm_JSAtom_inl_h
9
10 #include "vm/JSAtom.h"
11
12 #include "mozilla/FloatingPoint.h"
13 #include "mozilla/RangedPtr.h"
14
15 #include "jsnum.h"
16
17 #include "gc/MaybeRooted.h"
18 #include "vm/Runtime.h"
19 #include "vm/StringType.h"
20
21 namespace js {
22
AtomToId(JSAtom * atom)23 MOZ_ALWAYS_INLINE jsid AtomToId(JSAtom* atom) {
24 static_assert(JSID_INT_MIN == 0);
25
26 uint32_t index;
27 if (atom->isIndex(&index) && index <= JSID_INT_MAX) {
28 return INT_TO_JSID(int32_t(index));
29 }
30
31 return JS::PropertyKey::fromNonIntAtom(atom);
32 }
33
34 // Use the NameToId method instead!
35 inline jsid AtomToId(PropertyName* name) = delete;
36
ValueToIntId(const Value & v,jsid * id)37 MOZ_ALWAYS_INLINE bool ValueToIntId(const Value& v, jsid* id) {
38 int32_t i;
39 if (v.isInt32()) {
40 i = v.toInt32();
41 } else if (!v.isDouble() || !mozilla::NumberEqualsInt32(v.toDouble(), &i)) {
42 return false;
43 }
44
45 if (!INT_FITS_IN_JSID(i)) {
46 return false;
47 }
48
49 *id = INT_TO_JSID(i);
50 return true;
51 }
52
ValueToIdPure(const Value & v,jsid * id)53 inline bool ValueToIdPure(const Value& v, jsid* id) {
54 if (v.isString()) {
55 if (v.toString()->isAtom()) {
56 *id = AtomToId(&v.toString()->asAtom());
57 return true;
58 }
59 return false;
60 }
61
62 if (ValueToIntId(v, id)) {
63 return true;
64 }
65
66 if (v.isSymbol()) {
67 *id = SYMBOL_TO_JSID(v.toSymbol());
68 return true;
69 }
70
71 return false;
72 }
73
74 template <AllowGC allowGC>
PrimitiveValueToId(JSContext * cx,typename MaybeRooted<Value,allowGC>::HandleType v,typename MaybeRooted<jsid,allowGC>::MutableHandleType idp)75 inline bool PrimitiveValueToId(
76 JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType v,
77 typename MaybeRooted<jsid, allowGC>::MutableHandleType idp) {
78 // Non-primitive values should call ToPropertyKey.
79 MOZ_ASSERT(v.isPrimitive());
80
81 if (v.isString()) {
82 if (v.toString()->isAtom()) {
83 idp.set(AtomToId(&v.toString()->asAtom()));
84 return true;
85 }
86 } else {
87 if (ValueToIntId(v, idp.address())) {
88 return true;
89 }
90
91 if (v.isSymbol()) {
92 idp.set(SYMBOL_TO_JSID(v.toSymbol()));
93 return true;
94 }
95 }
96
97 JSAtom* atom = ToAtom<allowGC>(cx, v);
98 if (!atom) {
99 return false;
100 }
101
102 idp.set(AtomToId(atom));
103 return true;
104 }
105
106 /*
107 * Write out character representing |index| to the memory just before |end|.
108 * Thus |*end| is not touched, but |end[-1]| and earlier are modified as
109 * appropriate. There must be at least js::UINT32_CHAR_BUFFER_LENGTH elements
110 * before |end| to avoid buffer underflow. The start of the characters written
111 * is returned and is necessarily before |end|.
112 */
113 template <typename T>
BackfillIndexInCharBuffer(uint32_t index,mozilla::RangedPtr<T> end)114 inline mozilla::RangedPtr<T> BackfillIndexInCharBuffer(
115 uint32_t index, mozilla::RangedPtr<T> end) {
116 #ifdef DEBUG
117 /*
118 * Assert that the buffer we're filling will hold as many characters as we
119 * could write out, by dereferencing the index that would hold the most
120 * significant digit.
121 */
122 (void)*(end - UINT32_CHAR_BUFFER_LENGTH);
123 #endif
124
125 do {
126 uint32_t next = index / 10, digit = index % 10;
127 *--end = '0' + digit;
128 index = next;
129 } while (index > 0);
130
131 return end;
132 }
133
134 bool IndexToIdSlow(JSContext* cx, uint32_t index, MutableHandleId idp);
135
IndexToId(JSContext * cx,uint32_t index,MutableHandleId idp)136 inline bool IndexToId(JSContext* cx, uint32_t index, MutableHandleId idp) {
137 if (index <= JSID_INT_MAX) {
138 idp.set(INT_TO_JSID(index));
139 return true;
140 }
141
142 return IndexToIdSlow(cx, index, idp);
143 }
144
IdToString(JSContext * cx,jsid id)145 static MOZ_ALWAYS_INLINE JSLinearString* IdToString(JSContext* cx, jsid id) {
146 if (JSID_IS_STRING(id)) {
147 return id.toAtom();
148 }
149
150 if (MOZ_LIKELY(JSID_IS_INT(id))) {
151 return Int32ToString<CanGC>(cx, JSID_TO_INT(id));
152 }
153
154 RootedValue idv(cx, IdToValue(id));
155 JSString* str = ToStringSlow<CanGC>(cx, idv);
156 if (!str) {
157 return nullptr;
158 }
159
160 return str->ensureLinear(cx);
161 }
162
TypeName(JSType type,const JSAtomState & names)163 inline Handle<PropertyName*> TypeName(JSType type, const JSAtomState& names) {
164 MOZ_ASSERT(type < JSTYPE_LIMIT);
165 static_assert(offsetof(JSAtomState, undefined) +
166 JSTYPE_LIMIT * sizeof(ImmutablePropertyNamePtr) <=
167 sizeof(JSAtomState));
168 static_assert(JSTYPE_UNDEFINED == 0);
169 return (&names.undefined)[type];
170 }
171
ClassName(JSProtoKey key,JSAtomState & atomState)172 inline Handle<PropertyName*> ClassName(JSProtoKey key, JSAtomState& atomState) {
173 MOZ_ASSERT(key < JSProto_LIMIT);
174 static_assert(offsetof(JSAtomState, Null) +
175 JSProto_LIMIT * sizeof(ImmutablePropertyNamePtr) <=
176 sizeof(JSAtomState));
177 static_assert(JSProto_Null == 0);
178 return (&atomState.Null)[key];
179 }
180
181 } // namespace js
182
183 #endif /* vm_JSAtom_inl_h */
184