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 inline uint32_t JERRY_ATTR_ALWAYS_INLINE
lit_get_magic_string_ex_count(void)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 *
lit_get_magic_string_utf8(uint32_t id)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
lit_get_magic_string_size(uint32_t id)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
lit_get_magic_string_size_block_start(lit_utf8_size_t size)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 *
lit_get_magic_string_ex_utf8(uint32_t id)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
lit_get_magic_string_ex_size(uint32_t id)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
lit_magic_strings_ex_set(const lit_utf8_byte_t * const * ex_str_items,uint32_t count,const lit_utf8_size_t * ex_str_sizes)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
lit_is_utf8_string_magic(const lit_utf8_byte_t * string_p,lit_utf8_size_t string_size)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
lit_is_utf8_string_pair_magic(const lit_utf8_byte_t * string1_p,lit_utf8_size_t string1_size,const lit_utf8_byte_t * string2_p,lit_utf8_size_t string2_size)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
lit_is_ex_utf8_string_magic(const lit_utf8_byte_t * string_p,lit_utf8_size_t string_size)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
lit_is_ex_utf8_string_pair_magic(const lit_utf8_byte_t * string1_p,lit_utf8_size_t string1_size,const lit_utf8_byte_t * string2_p,lit_utf8_size_t string2_size)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 *
lit_copy_magic_string_to_buffer(lit_magic_string_id_t id,lit_utf8_byte_t * buffer_p,lit_utf8_size_t buffer_size)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