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 */
31inline uint32_t JERRY_ATTR_ALWAYS_INLINE
32lit_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 */
42const lit_utf8_byte_t *
43lit_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 */
67lit_utf8_size_t
68lit_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 */
93static lit_magic_string_id_t
94lit_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 */
119const lit_utf8_byte_t *
120lit_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 */
132lit_utf8_size_t
133lit_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 */
141void
142lit_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 */
202lit_magic_string_id_t
203lit_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 */
243lit_magic_string_id_t
244lit_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 */
295lit_magic_string_ex_id_t
296lit_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 */
352lit_magic_string_ex_id_t
353lit_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 */
419lit_utf8_byte_t *
420lit_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