1 | /* Copyright JS Foundation and other contributors, http://js.foundation |
2 | * |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
4 | * you may not use this file except in compliance with the License. |
5 | * You may obtain a copy of the License at |
6 | * |
7 | * http://www.apache.org/licenses/LICENSE-2.0 |
8 | * |
9 | * Unless required by applicable law or agreed to in writing, software |
10 | * distributed under the License is distributed on an "AS IS" BASIS |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | * See the License for the specific language governing permissions and |
13 | * limitations under the License. |
14 | */ |
15 | |
16 | #include "jcontext.h" |
17 | #include "lit-magic-strings.h" |
18 | #include "lit-strings.h" |
19 | |
20 | /** |
21 | * Maximum number of external magic strings that can be registered. |
22 | */ |
23 | #define LIT_EXTERNAL_MAGIC_STRING_LIMIT (UINT32_MAX / 2) |
24 | |
25 | /** |
26 | * Get number of external magic strings |
27 | * |
28 | * @return number of the strings, if there were registered, |
29 | * zero - otherwise. |
30 | */ |
31 | extern inline uint32_t JERRY_ATTR_ALWAYS_INLINE |
32 | lit_get_magic_string_ex_count (void) |
33 | { |
34 | return JERRY_CONTEXT (lit_magic_string_ex_count); |
35 | } /* lit_get_magic_string_ex_count */ |
36 | |
37 | /** |
38 | * Get specified magic string as zero-terminated string |
39 | * |
40 | * @return pointer to zero-terminated magic string |
41 | */ |
42 | const lit_utf8_byte_t * |
43 | lit_get_magic_string_utf8 (uint32_t id) /**< magic string id */ |
44 | { |
45 | static const lit_utf8_byte_t * const lit_magic_strings[] JERRY_ATTR_CONST_DATA = |
46 | { |
47 | /** @cond doxygen_suppress */ |
48 | #define LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE(size, id) |
49 | #define LIT_MAGIC_STRING_DEF(id, utf8_string) \ |
50 | (const lit_utf8_byte_t *) utf8_string, |
51 | #include "lit-magic-strings.inc.h" |
52 | #undef LIT_MAGIC_STRING_DEF |
53 | #undef LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE |
54 | /** @endcond */ |
55 | }; |
56 | |
57 | JERRY_ASSERT (id < LIT_NON_INTERNAL_MAGIC_STRING__COUNT); |
58 | |
59 | return lit_magic_strings[id]; |
60 | } /* lit_get_magic_string_utf8 */ |
61 | |
62 | /** |
63 | * Get size of specified magic string |
64 | * |
65 | * @return size in bytes |
66 | */ |
67 | lit_utf8_size_t |
68 | lit_get_magic_string_size (uint32_t id) /**< magic string id */ |
69 | { |
70 | static const lit_magic_size_t lit_magic_string_sizes[] JERRY_ATTR_CONST_DATA = |
71 | { |
72 | /** @cond doxygen_suppress */ |
73 | #define LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE(size, id) |
74 | #define LIT_MAGIC_STRING_DEF(id, utf8_string) \ |
75 | sizeof(utf8_string) - 1, |
76 | #include "lit-magic-strings.inc.h" |
77 | #undef LIT_MAGIC_STRING_DEF |
78 | #undef LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE |
79 | /** @endcond */ |
80 | }; |
81 | |
82 | JERRY_ASSERT (id < LIT_NON_INTERNAL_MAGIC_STRING__COUNT); |
83 | |
84 | return lit_magic_string_sizes[id]; |
85 | } /* lit_get_magic_string_size */ |
86 | |
87 | /** |
88 | * Get the block start element with the given size from |
89 | * the list of ECMA and implementation-defined magic string constants |
90 | * |
91 | * @return magic string id |
92 | */ |
93 | static lit_magic_string_id_t |
94 | lit_get_magic_string_size_block_start (lit_utf8_size_t size) /**< magic string size */ |
95 | { |
96 | static const lit_magic_string_id_t lit_magic_string_size_block_starts[] JERRY_ATTR_CONST_DATA = |
97 | { |
98 | /** @cond doxygen_suppress */ |
99 | #define LIT_MAGIC_STRING_DEF(id, utf8_string) |
100 | #define LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE(size, id) \ |
101 | id, |
102 | #include "lit-magic-strings.inc.h" |
103 | LIT_NON_INTERNAL_MAGIC_STRING__COUNT |
104 | #undef LIT_MAGIC_STRING_DEF |
105 | #undef LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE |
106 | /** @endcond */ |
107 | }; |
108 | |
109 | JERRY_ASSERT (size <= (sizeof (lit_magic_string_size_block_starts) / sizeof (lit_magic_string_id_t))); |
110 | |
111 | return lit_magic_string_size_block_starts[size]; |
112 | } /* lit_get_magic_string_size_block_start */ |
113 | |
114 | /** |
115 | * Get specified magic string as zero-terminated string from external table |
116 | * |
117 | * @return pointer to zero-terminated magic string |
118 | */ |
119 | const lit_utf8_byte_t * |
120 | lit_get_magic_string_ex_utf8 (uint32_t id) /**< extern magic string id */ |
121 | { |
122 | JERRY_ASSERT (JERRY_CONTEXT (lit_magic_string_ex_array) && id < JERRY_CONTEXT (lit_magic_string_ex_count)); |
123 | |
124 | return JERRY_CONTEXT (lit_magic_string_ex_array)[id]; |
125 | } /* lit_get_magic_string_ex_utf8 */ |
126 | |
127 | /** |
128 | * Get size of specified external magic string |
129 | * |
130 | * @return size in bytes |
131 | */ |
132 | lit_utf8_size_t |
133 | lit_get_magic_string_ex_size (uint32_t id) /**< external magic string id */ |
134 | { |
135 | return JERRY_CONTEXT (lit_magic_string_ex_sizes)[id]; |
136 | } /* lit_get_magic_string_ex_size */ |
137 | |
138 | /** |
139 | * Register external magic strings |
140 | */ |
141 | void |
142 | lit_magic_strings_ex_set (const lit_utf8_byte_t * const *ex_str_items, /**< character arrays, representing |
143 | * external magic strings' contents */ |
144 | uint32_t count, /**< number of the strings */ |
145 | const lit_utf8_size_t *ex_str_sizes) /**< sizes of the strings */ |
146 | { |
147 | JERRY_ASSERT (ex_str_items != NULL); |
148 | JERRY_ASSERT (count > 0); |
149 | JERRY_ASSERT (ex_str_sizes != NULL); |
150 | |
151 | JERRY_ASSERT (JERRY_CONTEXT (lit_magic_string_ex_array) == NULL); |
152 | JERRY_ASSERT (JERRY_CONTEXT (lit_magic_string_ex_count) == 0); |
153 | JERRY_ASSERT (JERRY_CONTEXT (lit_magic_string_ex_sizes) == NULL); |
154 | |
155 | /* Limit the number of external magic strings */ |
156 | if (count > LIT_EXTERNAL_MAGIC_STRING_LIMIT) |
157 | { |
158 | count = LIT_EXTERNAL_MAGIC_STRING_LIMIT; |
159 | } |
160 | |
161 | /* Set external magic strings information */ |
162 | JERRY_CONTEXT (lit_magic_string_ex_array) = ex_str_items; |
163 | JERRY_CONTEXT (lit_magic_string_ex_count) = count; |
164 | JERRY_CONTEXT (lit_magic_string_ex_sizes) = ex_str_sizes; |
165 | |
166 | #ifndef JERRY_NDEBUG |
167 | for (lit_magic_string_ex_id_t id = (lit_magic_string_ex_id_t) 0; |
168 | id < JERRY_CONTEXT (lit_magic_string_ex_count); |
169 | id = (lit_magic_string_ex_id_t) (id + 1)) |
170 | { |
171 | lit_utf8_size_t string_size = JERRY_CONTEXT (lit_magic_string_ex_sizes)[id]; |
172 | |
173 | /** |
174 | * Check whether the strings are sorted by size and lexicographically, |
175 | * e.g., "Bb" < "aa" < "aaa" < "xyz0". |
176 | */ |
177 | if (id > 0) |
178 | { |
179 | const lit_magic_string_ex_id_t prev_id = id - 1; |
180 | const lit_utf8_size_t prev_string_size = lit_get_magic_string_ex_size (prev_id); |
181 | JERRY_ASSERT (lit_is_valid_cesu8_string (lit_get_magic_string_ex_utf8 (id), |
182 | string_size)); |
183 | JERRY_ASSERT (prev_string_size <= string_size); |
184 | |
185 | if (prev_string_size == string_size) |
186 | { |
187 | const lit_utf8_byte_t *prev_ex_string_p = lit_get_magic_string_ex_utf8 (prev_id); |
188 | const lit_utf8_byte_t *curr_ex_string_p = lit_get_magic_string_ex_utf8 (id); |
189 | JERRY_ASSERT (memcmp (prev_ex_string_p, curr_ex_string_p, string_size) < 0); |
190 | } |
191 | } |
192 | } |
193 | #endif /* !JERRY_NDEBUG */ |
194 | } /* lit_magic_strings_ex_set */ |
195 | |
196 | /** |
197 | * Returns the magic string id of the argument string if it is available. |
198 | * |
199 | * @return id - if magic string id is found, |
200 | * LIT_MAGIC_STRING__COUNT - otherwise. |
201 | */ |
202 | lit_magic_string_id_t |
203 | lit_is_utf8_string_magic (const lit_utf8_byte_t *string_p, /**< utf-8 string */ |
204 | lit_utf8_size_t string_size) /**< string size in bytes */ |
205 | { |
206 | if (string_size > lit_get_magic_string_size (LIT_NON_INTERNAL_MAGIC_STRING__COUNT - 1)) |
207 | { |
208 | return LIT_MAGIC_STRING__COUNT; |
209 | } |
210 | |
211 | /**< The string must be in this id range. */ |
212 | lit_utf8_size_t first = lit_get_magic_string_size_block_start (string_size); |
213 | lit_utf8_size_t last = lit_get_magic_string_size_block_start (string_size + 1); |
214 | |
215 | while (first < last) |
216 | { |
217 | lit_utf8_size_t middle = ((first + last) / 2); /**< mid point of search */ |
218 | int compare = memcmp (lit_get_magic_string_utf8 ((lit_magic_string_id_t) middle), string_p, string_size); |
219 | |
220 | if (compare == 0) |
221 | { |
222 | return (lit_magic_string_id_t) middle; |
223 | } |
224 | else if (compare > 0) |
225 | { |
226 | last = middle; |
227 | } |
228 | else |
229 | { |
230 | first = middle + 1; |
231 | } |
232 | } |
233 | |
234 | return LIT_MAGIC_STRING__COUNT; |
235 | } /* lit_is_utf8_string_magic */ |
236 | |
237 | /** |
238 | * Returns the magic string id of the argument string pair if it is available. |
239 | * |
240 | * @return id - if magic string id is found, |
241 | * LIT_MAGIC_STRING__COUNT - otherwise. |
242 | */ |
243 | lit_magic_string_id_t |
244 | lit_is_utf8_string_pair_magic (const lit_utf8_byte_t *string1_p, /**< first utf-8 string */ |
245 | lit_utf8_size_t string1_size, /**< first string size in bytes */ |
246 | const lit_utf8_byte_t *string2_p, /**< second utf-8 string */ |
247 | lit_utf8_size_t string2_size) /**< second string size in bytes */ |
248 | { |
249 | lit_utf8_size_t total_string_size = string1_size + string2_size; |
250 | |
251 | if (total_string_size > lit_get_magic_string_size (LIT_NON_INTERNAL_MAGIC_STRING__COUNT - 1)) |
252 | { |
253 | return LIT_MAGIC_STRING__COUNT; |
254 | } |
255 | |
256 | /**< The string must be in this id range. */ |
257 | lit_utf8_size_t first = lit_get_magic_string_size_block_start (total_string_size); |
258 | lit_utf8_size_t last = lit_get_magic_string_size_block_start (total_string_size + 1); |
259 | |
260 | while (first < last) |
261 | { |
262 | lit_utf8_size_t middle = ((first + last) / 2); /**< mid point of search */ |
263 | const lit_utf8_byte_t *middle_string_p = lit_get_magic_string_utf8 ((lit_magic_string_id_t) middle); |
264 | |
265 | int compare = memcmp (middle_string_p, string1_p, string1_size); |
266 | |
267 | if (compare == 0) |
268 | { |
269 | compare = memcmp (middle_string_p + string1_size, string2_p, string2_size); |
270 | } |
271 | |
272 | if (compare == 0) |
273 | { |
274 | return (lit_magic_string_id_t) middle; |
275 | } |
276 | else if (compare > 0) |
277 | { |
278 | last = middle; |
279 | } |
280 | else |
281 | { |
282 | first = middle + 1; |
283 | } |
284 | } |
285 | |
286 | return LIT_MAGIC_STRING__COUNT; |
287 | } /* lit_is_utf8_string_pair_magic */ |
288 | |
289 | /** |
290 | * Returns the ex magic string id of the argument string if it is available. |
291 | * |
292 | * @return id - if magic string id is found, |
293 | * lit_get_magic_string_ex_count () - otherwise. |
294 | */ |
295 | lit_magic_string_ex_id_t |
296 | lit_is_ex_utf8_string_magic (const lit_utf8_byte_t *string_p, /**< utf-8 string */ |
297 | lit_utf8_size_t string_size) /**< string size in bytes */ |
298 | { |
299 | const uint32_t magic_string_ex_count = lit_get_magic_string_ex_count (); |
300 | |
301 | if (magic_string_ex_count == 0 |
302 | || string_size > lit_get_magic_string_ex_size (magic_string_ex_count - 1)) |
303 | { |
304 | return (lit_magic_string_ex_id_t) magic_string_ex_count; |
305 | } |
306 | |
307 | lit_magic_string_ex_id_t first = 0; |
308 | lit_magic_string_ex_id_t last = (lit_magic_string_ex_id_t) magic_string_ex_count; |
309 | |
310 | while (first < last) |
311 | { |
312 | const lit_magic_string_ex_id_t middle = (first + last) / 2; |
313 | const lit_utf8_byte_t *ext_string_p = lit_get_magic_string_ex_utf8 (middle); |
314 | const lit_utf8_size_t ext_string_size = lit_get_magic_string_ex_size (middle); |
315 | |
316 | if (string_size == ext_string_size) |
317 | { |
318 | const int string_compare = memcmp (ext_string_p, string_p, string_size); |
319 | |
320 | if (string_compare == 0) |
321 | { |
322 | return middle; |
323 | } |
324 | else if (string_compare < 0) |
325 | { |
326 | first = middle + 1; |
327 | } |
328 | else |
329 | { |
330 | last = middle; |
331 | } |
332 | } |
333 | else if (string_size > ext_string_size) |
334 | { |
335 | first = middle + 1; |
336 | } |
337 | else |
338 | { |
339 | last = middle; |
340 | } |
341 | } |
342 | |
343 | return (lit_magic_string_ex_id_t) magic_string_ex_count; |
344 | } /* lit_is_ex_utf8_string_magic */ |
345 | |
346 | /** |
347 | * Returns the ex magic string id of the argument string pair if it is available. |
348 | * |
349 | * @return id - if magic string id is found, |
350 | * lit_get_magic_string_ex_count () - otherwise. |
351 | */ |
352 | lit_magic_string_ex_id_t |
353 | lit_is_ex_utf8_string_pair_magic (const lit_utf8_byte_t *string1_p, /**< first utf-8 string */ |
354 | lit_utf8_size_t string1_size, /**< first string size in bytes */ |
355 | const lit_utf8_byte_t *string2_p, /**< second utf-8 string */ |
356 | lit_utf8_size_t string2_size) /**< second string size in bytes */ |
357 | { |
358 | const uint32_t magic_string_ex_count = lit_get_magic_string_ex_count (); |
359 | const lit_utf8_size_t total_string_size = string1_size + string2_size; |
360 | |
361 | if (magic_string_ex_count == 0 |
362 | || total_string_size > lit_get_magic_string_ex_size (magic_string_ex_count - 1)) |
363 | { |
364 | return (lit_magic_string_ex_id_t) magic_string_ex_count; |
365 | } |
366 | |
367 | lit_magic_string_ex_id_t first = 0; |
368 | lit_magic_string_ex_id_t last = (lit_magic_string_ex_id_t) magic_string_ex_count; |
369 | |
370 | while (first < last) |
371 | { |
372 | const lit_magic_string_ex_id_t middle = (first + last) / 2; |
373 | const lit_utf8_byte_t *ext_string_p = lit_get_magic_string_ex_utf8 (middle); |
374 | const lit_utf8_size_t ext_string_size = lit_get_magic_string_ex_size (middle); |
375 | |
376 | if (total_string_size == ext_string_size) |
377 | { |
378 | int string_compare = memcmp (ext_string_p, string1_p, string1_size); |
379 | |
380 | if (string_compare == 0) |
381 | { |
382 | string_compare = memcmp (ext_string_p + string1_size, string2_p, string2_size); |
383 | } |
384 | |
385 | if (string_compare == 0) |
386 | { |
387 | return middle; |
388 | } |
389 | else if (string_compare < 0) |
390 | { |
391 | first = middle + 1; |
392 | } |
393 | else |
394 | { |
395 | last = middle; |
396 | } |
397 | } |
398 | else if (total_string_size > ext_string_size) |
399 | { |
400 | first = middle + 1; |
401 | } |
402 | else |
403 | { |
404 | last = middle; |
405 | } |
406 | } |
407 | |
408 | return (lit_magic_string_ex_id_t) magic_string_ex_count; |
409 | } /* lit_is_ex_utf8_string_pair_magic */ |
410 | |
411 | /** |
412 | * Copy magic string to buffer |
413 | * |
414 | * Warning: |
415 | * the routine requires that buffer size is enough |
416 | * |
417 | * @return pointer to the byte next to the last copied in the buffer |
418 | */ |
419 | lit_utf8_byte_t * |
420 | lit_copy_magic_string_to_buffer (lit_magic_string_id_t id, /**< magic string id */ |
421 | lit_utf8_byte_t *buffer_p, /**< destination buffer */ |
422 | lit_utf8_size_t buffer_size) /**< size of buffer */ |
423 | { |
424 | const lit_utf8_byte_t *magic_string_bytes_p = lit_get_magic_string_utf8 (id); |
425 | lit_utf8_size_t magic_string_bytes_count = lit_get_magic_string_size (id); |
426 | |
427 | const lit_utf8_byte_t *str_iter_p = magic_string_bytes_p; |
428 | lit_utf8_byte_t *buf_iter_p = buffer_p; |
429 | lit_utf8_size_t bytes_copied = 0; |
430 | |
431 | while (magic_string_bytes_count--) |
432 | { |
433 | bytes_copied ++; |
434 | JERRY_ASSERT (bytes_copied <= buffer_size); |
435 | |
436 | *buf_iter_p++ = *str_iter_p++; |
437 | } |
438 | |
439 | return buf_iter_p; |
440 | } /* lit_copy_magic_string_to_buffer */ |
441 | |