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_StaticStrings_h
8 #define vm_StaticStrings_h
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/TextUtils.h"
16 #include <type_traits>
20 #include "js/TypeDecls.h"
22 class JS_PUBLIC_API JSTracer
;
23 struct JS_PUBLIC_API JSContext
;
32 class ParserAtomsTable
;
33 class TaggedParserAtomIndex
;
34 class WellKnownParserAtoms
;
35 struct CompilationAtomCache
;
36 } // namespace frontend
39 // NOTE: The WellKnownParserAtoms rely on these tables and may need to be
40 // update if these tables are changed.
41 friend class js::frontend::ParserAtomsTable
;
42 friend class js::frontend::TaggedParserAtomIndex
;
43 friend class js::frontend::WellKnownParserAtoms
;
44 friend struct js::frontend::CompilationAtomCache
;
47 // Strings matches `[A-Za-z0-9$_]{2}` pattern.
48 // Store each character in 6 bits.
49 // See fromSmallChar/toSmallChar for the mapping.
50 static constexpr size_t SMALL_CHAR_BITS
= 6;
51 static constexpr size_t SMALL_CHAR_MASK
= js::BitMask(SMALL_CHAR_BITS
);
53 // To optimize ASCII -> small char, allocate a table.
54 static constexpr size_t SMALL_CHAR_TABLE_SIZE
= 128U;
55 static constexpr size_t NUM_SMALL_CHARS
= js::Bit(SMALL_CHAR_BITS
);
56 static constexpr size_t NUM_LENGTH2_ENTRIES
=
57 NUM_SMALL_CHARS
* NUM_SMALL_CHARS
;
59 JSAtom
* length2StaticTable
[NUM_LENGTH2_ENTRIES
] = {}; // zeroes
62 /* We keep these public for the JITs. */
63 static const size_t UNIT_STATIC_LIMIT
= 256U;
64 JSAtom
* unitStaticTable
[UNIT_STATIC_LIMIT
] = {}; // zeroes
66 static const size_t INT_STATIC_LIMIT
= 256U;
67 JSAtom
* intStaticTable
[INT_STATIC_LIMIT
] = {}; // zeroes
69 StaticStrings() = default;
71 bool init(JSContext
* cx
);
72 void trace(JSTracer
* trc
);
74 static bool hasUint(uint32_t u
) { return u
< INT_STATIC_LIMIT
; }
76 JSAtom
* getUint(uint32_t u
) {
77 MOZ_ASSERT(hasUint(u
));
78 return intStaticTable
[u
];
81 static bool hasInt(int32_t i
) { return uint32_t(i
) < INT_STATIC_LIMIT
; }
83 JSAtom
* getInt(int32_t i
) {
84 MOZ_ASSERT(hasInt(i
));
85 return getUint(uint32_t(i
));
88 static bool hasUnit(char16_t c
) { return c
< UNIT_STATIC_LIMIT
; }
90 JSAtom
* getUnit(char16_t c
) {
91 MOZ_ASSERT(hasUnit(c
));
92 return unitStaticTable
[c
];
95 /* May not return atom, returns null on (reported) failure. */
96 inline JSLinearString
* getUnitStringForElement(JSContext
* cx
, JSString
* str
,
99 template <typename CharT
>
100 static bool isStatic(const CharT
* chars
, size_t len
);
102 /* Return null if no static atom exists for the given (chars, length). */
103 template <typename CharT
>
104 MOZ_ALWAYS_INLINE JSAtom
* lookup(const CharT
* chars
, size_t length
) {
105 static_assert(std::is_same_v
<CharT
, JS::Latin1Char
> ||
106 std::is_same_v
<CharT
, char16_t
>,
107 "for understandability, |chars| must be one of a few "
112 char16_t c
= chars
[0];
113 if (c
< UNIT_STATIC_LIMIT
) {
119 if (fitsInSmallChar(chars
[0]) && fitsInSmallChar(chars
[1])) {
120 return getLength2(chars
[0], chars
[1]);
125 * Here we know that JSString::intStringTable covers only 256 (or at
126 * least not 1000 or more) chars. We rely on order here to resolve the
127 * unit vs. int string/length-2 string atom identity issue by giving
128 * priority to unit strings for "0" through "9" and length-2 strings for
132 if (fitsInLength3Static(chars
[0], chars
[1], chars
[2], &i
)) {
141 MOZ_ALWAYS_INLINE JSAtom
* lookup(const char* chars
, size_t length
) {
142 // Collapse calls for |const char*| into |const Latin1Char char*| to avoid
143 // excess instantiations.
144 return lookup(reinterpret_cast<const JS::Latin1Char
*>(chars
), length
);
148 using SmallChar
= uint8_t;
150 struct SmallCharTable
{
151 SmallChar storage
[SMALL_CHAR_TABLE_SIZE
];
153 constexpr SmallChar
& operator[](size_t idx
) { return storage
[idx
]; }
154 constexpr const SmallChar
& operator[](size_t idx
) const {
159 static const SmallChar INVALID_SMALL_CHAR
= -1;
161 static bool fitsInSmallChar(char16_t c
) {
162 return c
< SMALL_CHAR_TABLE_SIZE
&&
163 toSmallCharTable
[c
] != INVALID_SMALL_CHAR
;
166 template <typename CharT
>
167 static bool fitsInLength3Static(CharT c1
, CharT c2
, CharT c3
, int* i
) {
168 static_assert(INT_STATIC_LIMIT
<= 299,
169 "static int strings assumed below to be at most "
170 "three digits where the first digit is either 1 or 2");
171 if ('1' <= c1
&& c1
< '3' && '0' <= c2
&& c2
<= '9' && '0' <= c3
&&
173 *i
= (c1
- '0') * 100 + (c2
- '0') * 10 + (c3
- '0');
175 if (unsigned(*i
) < INT_STATIC_LIMIT
) {
182 static constexpr JS::Latin1Char
fromSmallChar(SmallChar c
);
184 static constexpr SmallChar
toSmallChar(uint32_t c
);
186 static constexpr SmallCharTable
createSmallCharTable();
188 static const SmallCharTable toSmallCharTable
;
190 static constexpr JS::Latin1Char
firstCharOfLength2(size_t s
) {
191 return fromSmallChar(s
>> SMALL_CHAR_BITS
);
193 static constexpr JS::Latin1Char
secondCharOfLength2(size_t s
) {
194 return fromSmallChar(s
& SMALL_CHAR_MASK
);
197 static constexpr JS::Latin1Char
firstCharOfLength3(uint32_t i
) {
198 return '0' + (i
/ 100);
200 static constexpr JS::Latin1Char
secondCharOfLength3(uint32_t i
) {
201 return '0' + ((i
/ 10) % 10);
203 static constexpr JS::Latin1Char
thirdCharOfLength3(uint32_t i
) {
204 return '0' + (i
% 10);
207 static MOZ_ALWAYS_INLINE
size_t getLength2Index(char16_t c1
, char16_t c2
) {
208 MOZ_ASSERT(fitsInSmallChar(c1
));
209 MOZ_ASSERT(fitsInSmallChar(c2
));
210 return (size_t(toSmallCharTable
[c1
]) << SMALL_CHAR_BITS
) +
211 toSmallCharTable
[c2
];
214 // Same as getLength2Index, but withtout runtime assertion,
215 // this should be used only for known static string.
216 static constexpr size_t getLength2IndexStatic(char c1
, char c2
) {
217 return (size_t(toSmallChar(c1
)) << SMALL_CHAR_BITS
) + toSmallChar(c2
);
220 MOZ_ALWAYS_INLINE JSAtom
* getLength2FromIndex(size_t index
) {
221 return length2StaticTable
[index
];
224 MOZ_ALWAYS_INLINE JSAtom
* getLength2(char16_t c1
, char16_t c2
) {
225 return getLength2FromIndex(getLength2Index(c1
, c2
));
230 * Declare length-2 strings. We only store strings where both characters are
231 * alphanumeric. The lower 10 short chars are the numerals, the next 26 are
232 * the lowercase letters, and the next 26 are the uppercase letters.
235 constexpr JS::Latin1Char
StaticStrings::fromSmallChar(SmallChar c
) {
251 constexpr StaticStrings::SmallChar
StaticStrings::toSmallChar(uint32_t c
) {
252 if (mozilla::IsAsciiDigit(c
)) {
255 if (mozilla::IsAsciiLowercaseAlpha(c
)) {
258 if (mozilla::IsAsciiUppercaseAlpha(c
)) {
267 return StaticStrings::INVALID_SMALL_CHAR
;
272 #endif /* vm_StringType_h */