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 "ecma-alloc.h"
17#include "ecma-conversion.h"
18#include "ecma-gc.h"
19#include "ecma-globals.h"
20#include "ecma-helpers.h"
21#include "jrt.h"
22#include "jrt-libc-includes.h"
23#include "lit-char-helpers.h"
24#include "lit-magic-strings.h"
25
26/** \addtogroup ecma ECMA
27 * @{
28 *
29 * \addtogroup ecmahelpers Helpers for operations with ECMA data types
30 * @{
31 */
32
33JERRY_STATIC_ASSERT (ECMA_STRING_CONTAINER_MASK >= ECMA_STRING_CONTAINER__MAX,
34                     ecma_string_container_types_must_be_lower_than_the_container_mask);
35
36JERRY_STATIC_ASSERT ((ECMA_STRING_MAX_REF | ECMA_STRING_CONTAINER_MASK | ECMA_STATIC_STRING_FLAG) == UINT32_MAX,
37                     ecma_string_ref_and_container_fields_should_fill_the_32_bit_field);
38
39JERRY_STATIC_ASSERT (ECMA_STRING_NOT_ARRAY_INDEX == UINT32_MAX,
40                     ecma_string_not_array_index_must_be_equal_to_uint32_max);
41
42JERRY_STATIC_ASSERT ((ECMA_TYPE_DIRECT_STRING & 0x1) != 0,
43                     ecma_type_direct_string_must_be_odd_number);
44
45JERRY_STATIC_ASSERT (LIT_MAGIC_STRING__COUNT <= ECMA_DIRECT_STRING_MAX_IMM,
46                     all_magic_strings_must_be_encoded_as_direct_string);
47
48JERRY_STATIC_ASSERT ((int) ECMA_DIRECT_STRING_UINT == (int) ECMA_STRING_CONTAINER_UINT32_IN_DESC,
49                     ecma_direct_and_container_types_must_match);
50
51JERRY_STATIC_ASSERT (ECMA_PROPERTY_NAME_TYPE_SHIFT > ECMA_VALUE_SHIFT,
52                     ecma_property_name_type_shift_must_be_greater_than_ecma_value_shift);
53
54JERRY_STATIC_ASSERT (sizeof (ecma_stringbuilder_header_t) <= sizeof (ecma_ascii_string_t),
55                     ecma_stringbuilder_header_must_not_be_larger_than_ecma_ascii_string);
56
57/**
58 * Convert a string to an unsigned 32 bit value if possible
59 *
60 * @return true if the conversion is successful
61 *         false otherwise
62 */
63static bool
64ecma_string_to_array_index (const lit_utf8_byte_t *string_p, /**< utf-8 string */
65                            lit_utf8_size_t string_size, /**< string size */
66                            uint32_t *result_p) /**< [out] converted value */
67{
68  JERRY_ASSERT (string_size > 0 && *string_p >= LIT_CHAR_0 && *string_p <= LIT_CHAR_9);
69
70  if (*string_p == LIT_CHAR_0)
71  {
72    *result_p = 0;
73    return (string_size == 1);
74  }
75
76  if (string_size > ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32)
77  {
78    return false;
79  }
80
81  uint32_t index = 0;
82  const lit_utf8_byte_t *string_end_p = string_p + string_size;
83
84  if (string_size == ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32)
85  {
86    string_end_p--;
87  }
88
89  do
90  {
91    if (*string_p > LIT_CHAR_9 || *string_p < LIT_CHAR_0)
92    {
93      return false;
94    }
95
96    index = (index * 10) + (uint32_t) (*string_p++ - LIT_CHAR_0);
97  }
98  while (string_p < string_end_p);
99
100  if (string_size < ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32)
101  {
102    *result_p = index;
103    return true;
104  }
105
106  /* Overflow must be checked as well when size is
107   * equal to ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32. */
108  if (*string_p > LIT_CHAR_9
109      || *string_p < LIT_CHAR_0
110      || index > (UINT32_MAX / 10)
111      || (index == (UINT32_MAX / 10) && *string_p > LIT_CHAR_5))
112  {
113    return false;
114  }
115
116  *result_p = (index * 10) + (uint32_t) (*string_p - LIT_CHAR_0);
117  return true;
118} /* ecma_string_to_array_index */
119
120/**
121 * Returns the characters and size of a string.
122 *
123 * Note:
124 *   UINT type is not supported
125 *
126 * @return byte array start - if the byte array of a string is available
127 *         NULL - otherwise
128 */
129static const lit_utf8_byte_t *
130ecma_string_get_chars_fast (const ecma_string_t *string_p, /**< ecma-string */
131                            lit_utf8_size_t *size_p) /**< [out] size of the ecma string */
132{
133  if (ECMA_IS_DIRECT_STRING (string_p))
134  {
135    if (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC)
136    {
137      uint32_t id = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
138
139      if (id >= LIT_MAGIC_STRING__COUNT)
140      {
141        id -= LIT_MAGIC_STRING__COUNT;
142
143        *size_p = lit_get_magic_string_ex_size (id);
144        return lit_get_magic_string_ex_utf8 (id);
145      }
146
147      *size_p = lit_get_magic_string_size (id);
148      return lit_get_magic_string_utf8 (id);
149    }
150  }
151
152  JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE);
153
154  switch (ECMA_STRING_GET_CONTAINER (string_p))
155  {
156    case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING:
157    {
158      *size_p = ((ecma_utf8_string_t *) string_p)->size;
159      return ECMA_UTF8_STRING_GET_BUFFER (string_p);
160    }
161    case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING:
162    {
163      *size_p = ((ecma_long_utf8_string_t *) string_p)->size;
164      return ECMA_LONG_UTF8_STRING_GET_BUFFER (string_p);
165    }
166    case ECMA_STRING_CONTAINER_HEAP_ASCII_STRING:
167    {
168      *size_p = ((ecma_ascii_string_t *) string_p)->size;
169      return ECMA_ASCII_STRING_GET_BUFFER (string_p);
170    }
171    default:
172    {
173      JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);
174
175      lit_magic_string_ex_id_t id = LIT_MAGIC_STRING__COUNT - string_p->u.magic_string_ex_id;
176      *size_p = lit_get_magic_string_ex_size (id);
177      return lit_get_magic_string_ex_utf8 (id);
178    }
179  }
180} /* ecma_string_get_chars_fast */
181
182/**
183 * Allocate new ecma-string and fill it with reference to ECMA magic string
184 *
185 * @return pointer to ecma-string descriptor
186 */
187static ecma_string_t *
188ecma_new_ecma_string_from_magic_string_ex_id (lit_magic_string_ex_id_t id) /**< identifier of externl magic string */
189{
190  JERRY_ASSERT (id < lit_get_magic_string_ex_count ());
191
192  uintptr_t string_id = (uintptr_t) (id + LIT_MAGIC_STRING__COUNT);
193
194  if (JERRY_LIKELY (string_id <= ECMA_DIRECT_STRING_MAX_IMM))
195  {
196    return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_MAGIC, string_id);
197  }
198
199  ecma_string_t *string_desc_p = ecma_alloc_string ();
200
201  string_desc_p->refs_and_container = ECMA_STRING_CONTAINER_MAGIC_STRING_EX | ECMA_STRING_REF_ONE;
202  string_desc_p->u.magic_string_ex_id = id + LIT_MAGIC_STRING__COUNT;
203
204  return string_desc_p;
205} /* ecma_new_ecma_string_from_magic_string_ex_id */
206
207#if ENABLED (JERRY_ES2015)
208/**
209 * Allocate new ecma-string and fill it with reference to the symbol descriptor
210 *
211 * @return pointer to ecma-string descriptor
212 */
213ecma_string_t *
214ecma_new_symbol_from_descriptor_string (ecma_value_t string_desc) /**< ecma-string */
215{
216  JERRY_ASSERT (!ecma_is_value_symbol (string_desc));
217
218  ecma_extended_string_t *symbol_p = ecma_alloc_extended_string ();
219  symbol_p->header.refs_and_container = ECMA_STRING_REF_ONE | ECMA_STRING_CONTAINER_SYMBOL;
220  symbol_p->u.symbol_descriptor = string_desc;
221  symbol_p->header.u.hash = (lit_string_hash_t) (((uintptr_t) symbol_p) >> ECMA_SYMBOL_HASH_SHIFT);
222  JERRY_ASSERT ((symbol_p->header.u.hash & ECMA_GLOBAL_SYMBOL_FLAG) == 0);
223
224  return (ecma_string_t *) symbol_p;
225} /* ecma_new_symbol_from_descriptor_string */
226
227/**
228 * Check whether an ecma-string contains an ecma-symbol
229 *
230 * @return true - if the ecma-string contains an ecma-symbol
231 *         false - otherwise
232 */
233bool
234ecma_prop_name_is_symbol (ecma_string_t *string_p) /**< ecma-string */
235{
236  JERRY_ASSERT (string_p != NULL);
237
238  return (!ECMA_IS_DIRECT_STRING (string_p)
239          && ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_SYMBOL);
240} /* ecma_prop_name_is_symbol */
241#endif /* ENABLED (JERRY_ES2015) */
242
243/**
244 * Allocate new UTF8 ecma-string and fill it with characters from the given utf8 buffer
245 *
246 * @return pointer to ecma-string descriptor
247 */
248static inline ecma_string_t * JERRY_ATTR_ALWAYS_INLINE
249ecma_new_ecma_string_from_utf8_buffer (lit_utf8_size_t length, /**< length of the buffer */
250                                       lit_utf8_size_t size, /**< size of the buffer */
251                                       lit_utf8_byte_t **data_p) /**< [out] pointer to the start of the string buffer */
252{
253  if (JERRY_LIKELY (size <= UINT16_MAX))
254  {
255    if (JERRY_LIKELY (length == size))
256    {
257      ecma_ascii_string_t *string_desc_p;
258      string_desc_p = (ecma_ascii_string_t *) ecma_alloc_string_buffer (size + sizeof (ecma_ascii_string_t));
259      string_desc_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_ASCII_STRING | ECMA_STRING_REF_ONE;
260      string_desc_p->size = (uint16_t) size;
261
262      *data_p = ECMA_ASCII_STRING_GET_BUFFER (string_desc_p);
263      return (ecma_string_t *) string_desc_p;
264    }
265
266    JERRY_ASSERT (length < size);
267
268    ecma_utf8_string_t *string_desc_p;
269    string_desc_p = (ecma_utf8_string_t *) ecma_alloc_string_buffer (size + sizeof (ecma_utf8_string_t));
270    string_desc_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_UTF8_STRING | ECMA_STRING_REF_ONE;
271    string_desc_p->size = (uint16_t) size;
272    string_desc_p->length = (uint16_t) length;
273
274    *data_p = ECMA_UTF8_STRING_GET_BUFFER (string_desc_p);
275    return (ecma_string_t *) string_desc_p;
276  }
277
278  ecma_long_utf8_string_t *string_desc_p;
279  string_desc_p = (ecma_long_utf8_string_t *) ecma_alloc_string_buffer (size + sizeof (ecma_long_utf8_string_t));
280  string_desc_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING | ECMA_STRING_REF_ONE;
281  string_desc_p->size = size;
282  string_desc_p->length = length;
283
284  *data_p = ECMA_LONG_UTF8_STRING_GET_BUFFER (string_desc_p);
285  return (ecma_string_t *) string_desc_p;
286} /* ecma_new_ecma_string_from_utf8_buffer */
287
288/**
289 * Checks whether a string has a special representation, that is, the string is either a magic string,
290 * an external magic string, or an uint32 number, and creates an ecma string using the special representation,
291 * if available.
292 *
293 * @return pointer to ecma string with the special representation
294 *         NULL, if there is no special representation for the string
295 */
296ecma_string_t *
297ecma_find_special_string (const lit_utf8_byte_t *string_p, /**< utf8 string */
298                          lit_utf8_size_t string_size) /**< string size */
299{
300  JERRY_ASSERT (string_p != NULL || string_size == 0);
301  lit_magic_string_id_t magic_string_id = lit_is_utf8_string_magic (string_p, string_size);
302
303  if (magic_string_id != LIT_MAGIC_STRING__COUNT)
304  {
305    return ecma_get_magic_string (magic_string_id);
306  }
307
308  JERRY_ASSERT (string_size > 0);
309
310  if (*string_p >= LIT_CHAR_0 && *string_p <= LIT_CHAR_9)
311  {
312    uint32_t array_index;
313
314    if (ecma_string_to_array_index (string_p, string_size, &array_index))
315    {
316      return ecma_new_ecma_string_from_uint32 (array_index);
317    }
318  }
319
320  if (lit_get_magic_string_ex_count () > 0)
321  {
322    lit_magic_string_ex_id_t magic_string_ex_id = lit_is_ex_utf8_string_magic (string_p, string_size);
323
324    if (magic_string_ex_id < lit_get_magic_string_ex_count ())
325    {
326      return ecma_new_ecma_string_from_magic_string_ex_id (magic_string_ex_id);
327    }
328  }
329
330  return NULL;
331} /* ecma_find_special_string */
332
333/**
334 * Allocate new ecma-string and fill it with characters from the utf8 string
335 *
336 * @return pointer to ecma-string descriptor
337 */
338ecma_string_t *
339ecma_new_ecma_string_from_utf8 (const lit_utf8_byte_t *string_p, /**< utf-8 string */
340                                lit_utf8_size_t string_size) /**< string size */
341{
342  JERRY_ASSERT (string_p != NULL || string_size == 0);
343  JERRY_ASSERT (lit_is_valid_cesu8_string (string_p, string_size));
344
345  ecma_string_t *string_desc_p = ecma_find_special_string (string_p, string_size);
346
347  if (string_desc_p != NULL)
348  {
349    return string_desc_p;
350  }
351
352  lit_utf8_byte_t *data_p;
353  string_desc_p = ecma_new_ecma_string_from_utf8_buffer (lit_utf8_string_length (string_p, string_size),
354                                                         string_size,
355                                                         &data_p);
356
357  string_desc_p->u.hash = lit_utf8_string_calc_hash (string_p, string_size);
358  memcpy (data_p, string_p, string_size);
359
360  return string_desc_p;
361} /* ecma_new_ecma_string_from_utf8 */
362
363static ecma_long_utf8_string_t g_literalStringCache;
364
365ecma_string_t * ecma_new_nonref_ecma_string_from_utf8 (const lit_utf8_byte_t *string_p, lit_utf8_size_t size)
366{
367  ecma_length_t length = lit_utf8_string_length (string_p, size);
368
369  if  (JERRY_LIKELY (size <= UINT16_MAX))
370  {
371      if  (JERRY_LIKELY (length != size))
372       {
373           JERRY_ASSERT (length < size);
374           ecma_utf8_string_t *string_desc_p;
375           string_desc_p = (ecma_utf8_string_t *)&g_literalStringCache;
376           string_desc_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_UTF8_STRING | ECMA_STRING_REF_ONE;
377           string_desc_p->header.u.hash = lit_utf8_string_calc_hash (string_p, size);
378           string_desc_p->size = (uint16_t) size;
379           string_desc_p->length = (uint16_t) length;
380
381           return (ecma_string_t *) string_desc_p;
382       }
383
384       ecma_ascii_string_t *string_desc_p;
385       string_desc_p = (ecma_ascii_string_t *)&g_literalStringCache;
386       string_desc_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_ASCII_STRING | ECMA_STRING_REF_ONE;
387       string_desc_p->header.u.hash = lit_utf8_string_calc_hash (string_p, size);
388       string_desc_p->size = (uint16_t) size;
389
390       return (ecma_string_t *) string_desc_p;
391  }
392
393  ecma_long_utf8_string_t *string_desc_p;
394  string_desc_p = (ecma_long_utf8_string_t *)&g_literalStringCache;
395  string_desc_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING | ECMA_STRING_REF_ONE;
396  string_desc_p->header.u.hash = lit_utf8_string_calc_hash (string_p, size);
397  string_desc_p->size = size;
398  string_desc_p->length = length;
399
400  return  (ecma_string_t *) string_desc_p;
401}
402
403/**
404 * Allocate a new ecma-string and initialize it from the utf8 string argument.
405 * All 4-bytes long unicode sequences are converted into two 3-bytes long sequences.
406 *
407 * @return pointer to ecma-string descriptor
408 */
409ecma_string_t *
410ecma_new_ecma_string_from_utf8_converted_to_cesu8 (const lit_utf8_byte_t *string_p, /**< utf-8 string */
411                                                   lit_utf8_size_t string_size) /**< utf-8 string size */
412{
413  JERRY_ASSERT (string_p != NULL || string_size == 0);
414
415  ecma_length_t converted_string_length = 0;
416  lit_utf8_size_t converted_string_size = 0;
417  lit_utf8_size_t pos = 0;
418
419  /* Calculate the required length and size information of the converted cesu-8 encoded string */
420  while (pos < string_size)
421  {
422    if ((string_p[pos] & LIT_UTF8_1_BYTE_MASK) == LIT_UTF8_1_BYTE_MARKER)
423    {
424      pos++;
425    }
426    else if ((string_p[pos] & LIT_UTF8_2_BYTE_MASK) == LIT_UTF8_2_BYTE_MARKER)
427    {
428      pos += 2;
429    }
430    else if ((string_p[pos] & LIT_UTF8_3_BYTE_MASK) == LIT_UTF8_3_BYTE_MARKER)
431    {
432      pos += 3;
433    }
434    else
435    {
436      JERRY_ASSERT ((string_p[pos] & LIT_UTF8_4_BYTE_MASK) == LIT_UTF8_4_BYTE_MARKER);
437      pos += 4;
438      converted_string_size += 2;
439      converted_string_length++;
440    }
441
442    converted_string_length++;
443  }
444
445  JERRY_ASSERT (pos == string_size);
446
447  if (converted_string_size == 0)
448  {
449    return ecma_new_ecma_string_from_utf8 (string_p, string_size);
450  }
451
452  converted_string_size += string_size;
453
454  JERRY_ASSERT (lit_is_valid_utf8_string (string_p, string_size));
455
456  lit_utf8_byte_t *data_p;
457  ecma_string_t *string_desc_p = ecma_new_ecma_string_from_utf8_buffer (converted_string_length,
458                                                                        converted_string_size,
459                                                                        &data_p);
460
461  const lit_utf8_byte_t *const begin_data_p = data_p;
462  pos = 0;
463
464  while (pos < string_size)
465  {
466    if ((string_p[pos] & LIT_UTF8_4_BYTE_MASK) == LIT_UTF8_4_BYTE_MARKER)
467    {
468      /* Processing 4 byte unicode sequence. Always converted to two 3 byte long sequence. */
469      lit_four_byte_utf8_char_to_cesu8 (data_p, string_p + pos);
470      data_p += 3 * 2;
471      pos += 4;
472    }
473    else
474    {
475      *data_p++ = string_p[pos++];
476    }
477  }
478
479  JERRY_ASSERT (pos == string_size);
480
481  string_desc_p->u.hash = lit_utf8_string_calc_hash (begin_data_p, converted_string_size);
482
483  return (ecma_string_t *) string_desc_p;
484} /* ecma_new_ecma_string_from_utf8_converted_to_cesu8 */
485
486/**
487 * Allocate new ecma-string and fill it with cesu-8 character which represents specified code unit
488 *
489 * @return pointer to ecma-string descriptor
490 */
491ecma_string_t *
492ecma_new_ecma_string_from_code_unit (ecma_char_t code_unit) /**< code unit */
493{
494  lit_utf8_byte_t lit_utf8_bytes[LIT_UTF8_MAX_BYTES_IN_CODE_UNIT];
495  lit_utf8_size_t bytes_size = lit_code_unit_to_utf8 (code_unit, lit_utf8_bytes);
496
497  return ecma_new_ecma_string_from_utf8 (lit_utf8_bytes, bytes_size);
498} /* ecma_new_ecma_string_from_code_unit */
499
500#if ENABLED (JERRY_ES2015)
501
502/**
503 * Allocate new ecma-string and fill it with cesu-8 character which represents specified code units
504 *
505 * @return pointer to ecma-string descriptor
506 */
507ecma_string_t *
508ecma_new_ecma_string_from_code_units (ecma_char_t first_code_unit, /**< code unit */
509                                      ecma_char_t second_code_unit) /**< code unit */
510{
511  lit_utf8_byte_t lit_utf8_bytes[2 * LIT_UTF8_MAX_BYTES_IN_CODE_UNIT];
512  lit_utf8_size_t bytes_size = lit_code_unit_to_utf8 (first_code_unit, lit_utf8_bytes);
513  bytes_size += lit_code_unit_to_utf8 (second_code_unit, lit_utf8_bytes + bytes_size);
514
515  return ecma_new_ecma_string_from_utf8 (lit_utf8_bytes, bytes_size);
516} /* ecma_new_ecma_string_from_code_units */
517
518#endif /* ENABLED (JERRY_ES2015) */
519
520/**
521 * Allocate new ecma-string and fill it with ecma-number
522 *
523 * Note: the number cannot be represented as direct string
524 *
525 * @return pointer to ecma-string descriptor
526 */
527ecma_string_t *
528ecma_new_non_direct_string_from_uint32 (uint32_t uint32_number) /**< uint32 value of the string */
529{
530  JERRY_ASSERT (uint32_number > ECMA_DIRECT_STRING_MAX_IMM);
531
532  ecma_string_t *string_p = ecma_alloc_string ();
533
534  string_p->refs_and_container = ECMA_STRING_CONTAINER_UINT32_IN_DESC | ECMA_STRING_REF_ONE;
535  string_p->u.uint32_number = uint32_number;
536
537  return string_p;
538} /* ecma_new_non_direct_string_from_uint32 */
539
540/**
541 * Allocate new ecma-string and fill it with ecma-number
542 *
543 * @return pointer to ecma-string descriptor
544 */
545ecma_string_t *
546ecma_new_ecma_string_from_uint32 (uint32_t uint32_number) /**< uint32 value of the string */
547{
548  if (JERRY_LIKELY (uint32_number <= ECMA_DIRECT_STRING_MAX_IMM))
549  {
550    return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_UINT, (uintptr_t) uint32_number);
551  }
552
553  return ecma_new_non_direct_string_from_uint32 (uint32_number);
554} /* ecma_new_ecma_string_from_uint32 */
555
556/**
557 * Returns the constant assigned to the uint32 number.
558 *
559 * Note:
560 *   Calling ecma_deref_ecma_string on the returned pointer is optional.
561 *
562 * @return pointer to ecma-string descriptor
563 */
564ecma_string_t *
565ecma_get_ecma_string_from_uint32 (uint32_t uint32_number) /**< input number */
566{
567  JERRY_ASSERT (uint32_number <= ECMA_DIRECT_STRING_MAX_IMM);
568
569  return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_UINT, (uintptr_t) uint32_number);
570} /* ecma_get_ecma_string_from_uint32 */
571
572/**
573 * Allocate new ecma-string and fill it with ecma-number
574 *
575 * @return pointer to ecma-string descriptor
576 */
577ecma_string_t *
578ecma_new_ecma_string_from_number (ecma_number_t num) /**< ecma-number */
579{
580  uint32_t uint32_num = ecma_number_to_uint32 (num);
581  if (num == ((ecma_number_t) uint32_num))
582  {
583    return ecma_new_ecma_string_from_uint32 (uint32_num);
584  }
585
586  if (ecma_number_is_nan (num))
587  {
588    return ecma_get_magic_string (LIT_MAGIC_STRING_NAN);
589  }
590
591  if (ecma_number_is_infinity (num))
592  {
593    lit_magic_string_id_t id = (ecma_number_is_negative (num) ? LIT_MAGIC_STRING_NEGATIVE_INFINITY_UL
594                                                              : LIT_MAGIC_STRING_INFINITY_UL);
595    return ecma_get_magic_string (id);
596  }
597
598  lit_utf8_byte_t str_buf[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER];
599  lit_utf8_size_t str_size = ecma_number_to_utf8_string (num, str_buf, sizeof (str_buf));
600
601  JERRY_ASSERT (str_size > 0);
602#ifndef JERRY_NDEBUG
603  JERRY_ASSERT (lit_is_utf8_string_magic (str_buf, str_size) == LIT_MAGIC_STRING__COUNT
604                && lit_is_ex_utf8_string_magic (str_buf, str_size) == lit_get_magic_string_ex_count ());
605#endif /* !JERRY_NDEBUG */
606
607  lit_utf8_byte_t *data_p;
608  ecma_string_t *string_desc_p = ecma_new_ecma_string_from_utf8_buffer (lit_utf8_string_length (str_buf, str_size),
609                                                                        str_size,
610                                                                        &data_p);
611
612  string_desc_p->u.hash = lit_utf8_string_calc_hash (str_buf, str_size);
613  memcpy (data_p, str_buf, str_size);
614
615  return string_desc_p;
616} /* ecma_new_ecma_string_from_number */
617
618/**
619 * Returns the constant assigned to the magic string id.
620 *
621 * Note:
622 *   Calling ecma_deref_ecma_string on the returned pointer is optional.
623 *
624 * @return pointer to ecma-string descriptor
625 */
626extern inline ecma_string_t * JERRY_ATTR_ALWAYS_INLINE
627ecma_get_magic_string (lit_magic_string_id_t id) /**< identifier of magic string */
628{
629  JERRY_ASSERT (id < LIT_MAGIC_STRING__COUNT);
630  return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_MAGIC, (uintptr_t) id);
631} /* ecma_get_magic_string */
632
633/**
634 * Append a cesu8 string after an ecma-string
635 *
636 * Note:
637 *   The string1_p argument is freed. If it needs to be preserved,
638 *   call ecma_ref_ecma_string with string1_p before the call.
639 *
640 * @return concatenation of an ecma-string and a cesu8 string
641 */
642ecma_string_t *
643ecma_append_chars_to_string (ecma_string_t *string1_p, /**< base ecma-string */
644                             const lit_utf8_byte_t *cesu8_string2_p, /**< characters to be appended */
645                             lit_utf8_size_t cesu8_string2_size, /**< byte size of cesu8_string2_p */
646                             lit_utf8_size_t cesu8_string2_length) /**< character length of cesu8_string2_p */
647{
648  JERRY_ASSERT (string1_p != NULL && cesu8_string2_size > 0 && cesu8_string2_length > 0);
649
650  if (JERRY_UNLIKELY (ecma_string_is_empty (string1_p)))
651  {
652    return ecma_new_ecma_string_from_utf8 (cesu8_string2_p, cesu8_string2_size);
653  }
654
655  lit_utf8_size_t cesu8_string1_size;
656  lit_utf8_size_t cesu8_string1_length;
657  uint8_t flags = ECMA_STRING_FLAG_IS_ASCII;
658  lit_utf8_byte_t uint32_to_string_buffer[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32];
659
660  const lit_utf8_byte_t *cesu8_string1_p = ecma_string_get_chars (string1_p,
661                                                                  &cesu8_string1_size,
662                                                                  &cesu8_string1_length,
663                                                                  uint32_to_string_buffer,
664                                                                  &flags);
665
666  JERRY_ASSERT (!(flags & ECMA_STRING_FLAG_MUST_BE_FREED));
667  JERRY_ASSERT (cesu8_string1_length > 0);
668  JERRY_ASSERT (cesu8_string1_length <= cesu8_string1_size);
669
670  lit_utf8_size_t new_size = cesu8_string1_size + cesu8_string2_size;
671
672  /* Poor man's carry flag check: it is impossible to allocate this large string. */
673  if (new_size < (cesu8_string1_size | cesu8_string2_size))
674  {
675    jerry_fatal (ERR_OUT_OF_MEMORY);
676  }
677
678  lit_magic_string_id_t magic_string_id;
679  magic_string_id = lit_is_utf8_string_pair_magic (cesu8_string1_p,
680                                                   cesu8_string1_size,
681                                                   cesu8_string2_p,
682                                                   cesu8_string2_size);
683
684  if (magic_string_id != LIT_MAGIC_STRING__COUNT)
685  {
686    ecma_deref_ecma_string (string1_p);
687    return ecma_get_magic_string (magic_string_id);
688  }
689
690  if ((flags & ECMA_STRING_FLAG_IS_UINT32) && new_size <= ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32)
691  {
692    memcpy (uint32_to_string_buffer + cesu8_string1_size, cesu8_string2_p, cesu8_string2_size);
693
694    uint32_t array_index;
695
696    if (ecma_string_to_array_index (uint32_to_string_buffer, new_size, &array_index))
697    {
698      ecma_deref_ecma_string (string1_p);
699      return ecma_new_ecma_string_from_uint32 (array_index);
700    }
701  }
702
703  if (lit_get_magic_string_ex_count () > 0)
704  {
705    lit_magic_string_ex_id_t magic_string_ex_id;
706    magic_string_ex_id = lit_is_ex_utf8_string_pair_magic (cesu8_string1_p,
707                                                           cesu8_string1_size,
708                                                           cesu8_string2_p,
709                                                           cesu8_string2_size);
710
711    if (magic_string_ex_id < lit_get_magic_string_ex_count ())
712    {
713      ecma_deref_ecma_string (string1_p);
714      return ecma_new_ecma_string_from_magic_string_ex_id (magic_string_ex_id);
715    }
716  }
717
718  lit_utf8_byte_t *data_p;
719  ecma_string_t *string_desc_p = ecma_new_ecma_string_from_utf8_buffer (cesu8_string1_length + cesu8_string2_length,
720                                                                        new_size,
721                                                                        &data_p);
722
723  lit_string_hash_t hash_start;
724
725  if (JERRY_UNLIKELY (flags & ECMA_STRING_FLAG_REHASH_NEEDED))
726  {
727    hash_start = lit_utf8_string_calc_hash (cesu8_string1_p, cesu8_string1_size);
728  }
729  else
730  {
731    JERRY_ASSERT (!ECMA_IS_DIRECT_STRING (string1_p));
732    hash_start = string1_p->u.hash;
733  }
734
735  string_desc_p->u.hash = lit_utf8_string_hash_combine (hash_start, cesu8_string2_p, cesu8_string2_size);
736
737  memcpy (data_p, cesu8_string1_p, cesu8_string1_size);
738  memcpy (data_p + cesu8_string1_size, cesu8_string2_p, cesu8_string2_size);
739
740  ecma_deref_ecma_string (string1_p);
741  return (ecma_string_t *) string_desc_p;
742} /* ecma_append_chars_to_string */
743
744/**
745 * Concatenate ecma-strings
746 *
747 * Note:
748 *   The string1_p argument is freed. If it needs to be preserved,
749 *   call ecma_ref_ecma_string with string1_p before the call.
750 *
751 * @return concatenation of two ecma-strings
752 */
753ecma_string_t *
754ecma_concat_ecma_strings (ecma_string_t *string1_p, /**< first ecma-string */
755                          ecma_string_t *string2_p) /**< second ecma-string */
756{
757  JERRY_ASSERT (string1_p != NULL && string2_p != NULL);
758
759  if (JERRY_UNLIKELY (ecma_string_is_empty (string1_p)))
760  {
761    ecma_ref_ecma_string (string2_p);
762    return string2_p;
763  }
764  else if (JERRY_UNLIKELY (ecma_string_is_empty (string2_p)))
765  {
766    return string1_p;
767  }
768
769  lit_utf8_size_t cesu8_string2_size;
770  lit_utf8_size_t cesu8_string2_length;
771  lit_utf8_byte_t uint32_to_string_buffer[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32];
772  uint8_t flags = ECMA_STRING_FLAG_IS_ASCII;
773
774  const lit_utf8_byte_t *cesu8_string2_p = ecma_string_get_chars (string2_p,
775                                                                  &cesu8_string2_size,
776                                                                  &cesu8_string2_length,
777                                                                  uint32_to_string_buffer,
778                                                                  &flags);
779
780  JERRY_ASSERT (cesu8_string2_p != NULL);
781
782  ecma_string_t *result_p = ecma_append_chars_to_string (string1_p,
783                                                         cesu8_string2_p,
784                                                         cesu8_string2_size,
785                                                         cesu8_string2_length);
786
787  JERRY_ASSERT (!(flags & ECMA_STRING_FLAG_MUST_BE_FREED));
788
789  return result_p;
790} /* ecma_concat_ecma_strings */
791
792/**
793 * Increase reference counter of ecma-string.
794 */
795void
796ecma_ref_ecma_string (ecma_string_t *string_p) /**< string descriptor */
797{
798  JERRY_ASSERT (string_p != NULL);
799
800  if (ECMA_IS_DIRECT_STRING (string_p))
801  {
802    return;
803  }
804
805#ifdef JERRY_NDEBUG
806  if (ECMA_STRING_IS_STATIC (string_p))
807  {
808    return;
809  }
810#endif /* JERRY_NDEBUG */
811
812  JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE);
813
814  if (JERRY_LIKELY (string_p->refs_and_container < ECMA_STRING_MAX_REF))
815  {
816    /* Increase reference counter. */
817    string_p->refs_and_container += ECMA_STRING_REF_ONE;
818  }
819  else
820  {
821    jerry_fatal (ERR_REF_COUNT_LIMIT);
822  }
823} /* ecma_ref_ecma_string */
824
825/**
826 * Decrease reference counter and deallocate ecma-string
827 * if the counter becomes zero.
828 */
829void
830ecma_deref_ecma_string (ecma_string_t *string_p) /**< ecma-string */
831{
832  JERRY_ASSERT (string_p != NULL);
833
834  if (ECMA_IS_DIRECT_STRING (string_p))
835  {
836    return;
837  }
838
839#ifdef JERRY_NDEBUG
840  if (ECMA_STRING_IS_STATIC (string_p))
841  {
842    return;
843  }
844#endif /* JERRY_NDEBUG */
845
846  JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE);
847
848  /* Decrease reference counter. */
849  string_p->refs_and_container -= ECMA_STRING_REF_ONE;
850
851  if (string_p->refs_and_container >= ECMA_STRING_REF_ONE)
852  {
853    return;
854  }
855
856  ecma_destroy_ecma_string (string_p);
857} /* ecma_deref_ecma_string */
858
859/**
860 * Deallocate an ecma-string
861 */
862void
863ecma_destroy_ecma_string (ecma_string_t *string_p) /**< ecma-string */
864{
865  JERRY_ASSERT (string_p != NULL);
866  JERRY_ASSERT (!ECMA_IS_DIRECT_STRING (string_p));
867  JERRY_ASSERT ((string_p->refs_and_container < ECMA_STRING_REF_ONE) || ECMA_STRING_IS_STATIC (string_p));
868
869  switch (ECMA_STRING_GET_CONTAINER (string_p))
870  {
871    case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING:
872    {
873      ecma_dealloc_string_buffer (string_p, ((ecma_utf8_string_t *) string_p)->size + sizeof (ecma_utf8_string_t));
874      return;
875    }
876    case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING:
877    {
878      ecma_dealloc_string_buffer (string_p,
879                                  ((ecma_long_utf8_string_t *) string_p)->size + sizeof (ecma_long_utf8_string_t));
880      return;
881    }
882    case ECMA_STRING_CONTAINER_HEAP_ASCII_STRING:
883    {
884      ecma_dealloc_string_buffer (string_p,
885                                  ((ecma_ascii_string_t *) string_p)->size + sizeof (ecma_ascii_string_t));
886      return;
887    }
888#if ENABLED (JERRY_ES2015)
889    case ECMA_STRING_CONTAINER_SYMBOL:
890    {
891      ecma_extended_string_t * symbol_p = (ecma_extended_string_t *) string_p;
892      ecma_free_value (symbol_p->u.symbol_descriptor);
893      ecma_dealloc_extended_string (symbol_p);
894      return;
895    }
896#endif /* ENABLED (JERRY_ES2015) */
897    default:
898    {
899      JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC
900                    || ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);
901
902      /* only the string descriptor itself should be freed */
903      ecma_dealloc_string (string_p);
904    }
905  }
906} /* ecma_destroy_ecma_string */
907
908/**
909 * Convert ecma-string to number
910 *
911 * @return converted ecma-number
912 */
913ecma_number_t
914ecma_string_to_number (const ecma_string_t *string_p) /**< ecma-string */
915{
916  JERRY_ASSERT (string_p != NULL);
917
918  if (ECMA_IS_DIRECT_STRING (string_p))
919  {
920    if (ECMA_IS_DIRECT_STRING_WITH_TYPE (string_p, ECMA_DIRECT_STRING_UINT))
921    {
922      return (ecma_number_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
923    }
924  }
925  else if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
926  {
927    return ((ecma_number_t) string_p->u.uint32_number);
928  }
929
930  lit_utf8_size_t size;
931  const lit_utf8_byte_t *chars_p = ecma_string_get_chars_fast (string_p, &size);
932
933  JERRY_ASSERT (chars_p != NULL);
934
935  if (size == 0)
936  {
937    return ECMA_NUMBER_ZERO;
938  }
939
940  return ecma_utf8_string_to_number (chars_p, size);
941} /* ecma_string_to_number */
942
943/**
944 * Check if string is array index.
945 *
946 * @return ECMA_STRING_NOT_ARRAY_INDEX if string is not array index
947 *         the array index otherwise
948 */
949inline uint32_t JERRY_ATTR_ALWAYS_INLINE
950ecma_string_get_array_index (const ecma_string_t *str_p) /**< ecma-string */
951{
952  if (ECMA_IS_DIRECT_STRING (str_p))
953  {
954    if (ECMA_IS_DIRECT_STRING_WITH_TYPE (str_p, ECMA_DIRECT_STRING_UINT))
955    {
956      /* Value cannot be equal to the maximum value of a 32 bit unsigned number. */
957      return (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (str_p);
958    }
959
960    return ECMA_STRING_NOT_ARRAY_INDEX;
961  }
962
963  if (ECMA_STRING_GET_CONTAINER (str_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
964  {
965    /* When the uint32_number is equal to the maximum value of 32 bit unsigned integer number,
966     * it is also an invalid array index. The comparison to ECMA_STRING_NOT_ARRAY_INDEX will
967     * be true in this case. */
968    return str_p->u.uint32_number;
969  }
970
971  return ECMA_STRING_NOT_ARRAY_INDEX;
972} /* ecma_string_get_array_index */
973
974/**
975 * Convert ecma-string's contents to a cesu-8 string and put it to the buffer.
976 * It is the caller's responsibility to make sure that the string fits in the buffer.
977 *
978 * @return number of bytes, actually copied to the buffer.
979 */
980lit_utf8_size_t JERRY_ATTR_WARN_UNUSED_RESULT
981ecma_string_copy_to_cesu8_buffer (const ecma_string_t *string_p, /**< ecma-string descriptor */
982                                  lit_utf8_byte_t *buffer_p, /**< destination buffer pointer
983                                                              * (can be NULL if buffer_size == 0) */
984                                  lit_utf8_size_t buffer_size) /**< size of buffer */
985{
986  JERRY_ASSERT (string_p != NULL);
987  JERRY_ASSERT (buffer_p != NULL || buffer_size == 0);
988  JERRY_ASSERT (ecma_string_get_size (string_p) <= buffer_size);
989
990  lit_utf8_size_t size;
991
992  if (ECMA_IS_DIRECT_STRING (string_p))
993  {
994    if (ECMA_IS_DIRECT_STRING_WITH_TYPE (string_p, ECMA_DIRECT_STRING_UINT))
995    {
996      uint32_t uint32_number = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
997      size = ecma_uint32_to_utf8_string (uint32_number, buffer_p, buffer_size);
998      JERRY_ASSERT (size <= buffer_size);
999      return size;
1000    }
1001  }
1002  else
1003  {
1004    JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE);
1005
1006    if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
1007    {
1008      uint32_t uint32_number = string_p->u.uint32_number;
1009      size = ecma_uint32_to_utf8_string (uint32_number, buffer_p, buffer_size);
1010      JERRY_ASSERT (size <= buffer_size);
1011      return size;
1012    }
1013  }
1014
1015  const lit_utf8_byte_t *chars_p = ecma_string_get_chars_fast (string_p, &size);
1016
1017  JERRY_ASSERT (chars_p != NULL);
1018  JERRY_ASSERT (size <= buffer_size);
1019
1020  memcpy (buffer_p, chars_p, size);
1021  return size;
1022} /* ecma_string_copy_to_cesu8_buffer */
1023
1024/**
1025 * Convert ecma-string's contents to an utf-8 string and put it to the buffer.
1026 * It is the caller's responsibility to make sure that the string fits in the buffer.
1027 *
1028 * @return number of bytes, actually copied to the buffer.
1029 */
1030lit_utf8_size_t JERRY_ATTR_WARN_UNUSED_RESULT
1031ecma_string_copy_to_utf8_buffer (const ecma_string_t *string_p, /**< ecma-string descriptor */
1032                                 lit_utf8_byte_t *buffer_p, /**< destination buffer pointer
1033                                                             * (can be NULL if buffer_size == 0) */
1034                                 lit_utf8_size_t buffer_size) /**< size of buffer */
1035{
1036  JERRY_ASSERT (string_p != NULL);
1037  JERRY_ASSERT (buffer_p != NULL || buffer_size == 0);
1038  JERRY_ASSERT (ecma_string_get_utf8_size (string_p) <= buffer_size);
1039
1040  lit_utf8_size_t size;
1041
1042  if (ECMA_IS_DIRECT_STRING (string_p))
1043  {
1044    if (ECMA_IS_DIRECT_STRING_WITH_TYPE (string_p, ECMA_DIRECT_STRING_UINT))
1045    {
1046      uint32_t uint32_number = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
1047      size = ecma_uint32_to_utf8_string (uint32_number, buffer_p, buffer_size);
1048      JERRY_ASSERT (size <= buffer_size);
1049      return size;
1050    }
1051  }
1052  else
1053  {
1054    JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE);
1055
1056    if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
1057    {
1058      uint32_t uint32_number = string_p->u.uint32_number;
1059      size = ecma_uint32_to_utf8_string (uint32_number, buffer_p, buffer_size);
1060      JERRY_ASSERT (size <= buffer_size);
1061      return size;
1062    }
1063  }
1064
1065  uint8_t flags = ECMA_STRING_FLAG_IS_ASCII;
1066  const lit_utf8_byte_t *chars_p = ecma_string_get_chars (string_p, &size, NULL, NULL, &flags);
1067
1068  JERRY_ASSERT (chars_p != NULL);
1069
1070  if (flags & ECMA_STRING_FLAG_IS_ASCII)
1071  {
1072    JERRY_ASSERT (size <= buffer_size);
1073    memcpy (buffer_p, chars_p, size);
1074    return size;
1075  }
1076
1077  size = lit_convert_cesu8_string_to_utf8_string (chars_p,
1078                                                  size,
1079                                                  buffer_p,
1080                                                  buffer_size);
1081
1082  if (flags & ECMA_STRING_FLAG_MUST_BE_FREED)
1083  {
1084    jmem_heap_free_block ((void *) chars_p, size);
1085  }
1086
1087  JERRY_ASSERT (size <= buffer_size);
1088  return size;
1089} /* ecma_string_copy_to_utf8_buffer */
1090
1091/**
1092 * Convert ecma-string's contents to a cesu-8 string, extract the parts of the converted string between the specified
1093 * start position and the end position (or the end of the string, whichever comes first), and copy these characters
1094 * into the buffer.
1095 *
1096 * @return number of bytes, actually copied to the buffer.
1097 */
1098lit_utf8_size_t
1099ecma_substring_copy_to_cesu8_buffer (const ecma_string_t *string_desc_p, /**< ecma-string descriptor */
1100                                     ecma_length_t start_pos, /**< position of the first character */
1101                                     ecma_length_t end_pos, /**< position of the last character */
1102                                     lit_utf8_byte_t *buffer_p, /**< destination buffer pointer
1103                                                                 * (can be NULL if buffer_size == 0) */
1104                                     lit_utf8_size_t buffer_size) /**< size of buffer */
1105{
1106  JERRY_ASSERT (string_desc_p != NULL);
1107  JERRY_ASSERT (buffer_p != NULL || buffer_size == 0);
1108
1109  ecma_length_t string_length = ecma_string_get_length (string_desc_p);
1110  lit_utf8_size_t size = 0;
1111
1112  if (start_pos >= string_length || start_pos >= end_pos)
1113  {
1114    return 0;
1115  }
1116
1117  if (end_pos > string_length)
1118  {
1119    end_pos = string_length;
1120  }
1121
1122  ECMA_STRING_TO_UTF8_STRING (string_desc_p, utf8_str_p, utf8_str_size);
1123
1124  const lit_utf8_byte_t *start_p = utf8_str_p;
1125
1126  if (string_length == utf8_str_size)
1127  {
1128    start_p += start_pos;
1129    size = end_pos - start_pos;
1130
1131    if (size > buffer_size)
1132    {
1133      size = buffer_size;
1134    }
1135
1136    memcpy (buffer_p, start_p, size);
1137  }
1138  else
1139  {
1140    end_pos -= start_pos;
1141    while (start_pos--)
1142    {
1143      start_p += lit_get_unicode_char_size_by_utf8_first_byte (*start_p);
1144    }
1145
1146    const lit_utf8_byte_t *end_p = start_p;
1147
1148    while (end_pos--)
1149    {
1150      lit_utf8_size_t code_unit_size = lit_get_unicode_char_size_by_utf8_first_byte (*end_p);
1151
1152      if ((size + code_unit_size) > buffer_size)
1153      {
1154        break;
1155      }
1156
1157      end_p += code_unit_size;
1158      size += code_unit_size;
1159    }
1160
1161    memcpy (buffer_p, start_p, size);
1162  }
1163
1164  ECMA_FINALIZE_UTF8_STRING (utf8_str_p, utf8_str_size);
1165
1166  JERRY_ASSERT (size <= buffer_size);
1167  return size;
1168} /* ecma_substring_copy_to_cesu8_buffer */
1169
1170/**
1171 * Convert ecma-string's contents to an utf-8 string, extract the parts of the converted string between the specified
1172 * start position and the end position (or the end of the string, whichever comes first), and copy these characters
1173 * into the buffer.
1174 *
1175 * @return number of bytes, actually copied to the buffer.
1176 */
1177lit_utf8_size_t
1178ecma_substring_copy_to_utf8_buffer (const ecma_string_t *string_desc_p, /**< ecma-string descriptor */
1179                                    ecma_length_t start_pos, /**< position of the first character */
1180                                    ecma_length_t end_pos, /**< position of the last character */
1181                                    lit_utf8_byte_t *buffer_p, /**< destination buffer pointer
1182                                                                * (can be NULL if buffer_size == 0) */
1183                                    lit_utf8_size_t buffer_size) /**< size of buffer */
1184{
1185  JERRY_ASSERT (string_desc_p != NULL);
1186  JERRY_ASSERT (ECMA_IS_DIRECT_STRING (string_desc_p) || string_desc_p->refs_and_container >= ECMA_STRING_REF_ONE);
1187  JERRY_ASSERT (buffer_p != NULL || buffer_size == 0);
1188
1189  lit_utf8_size_t size = 0;
1190
1191  ecma_length_t utf8_str_length = ecma_string_get_utf8_length (string_desc_p);
1192
1193  if (start_pos >= utf8_str_length || start_pos >= end_pos)
1194  {
1195    return 0;
1196  }
1197
1198  if (end_pos > utf8_str_length)
1199  {
1200    end_pos = utf8_str_length;
1201  }
1202
1203  ECMA_STRING_TO_UTF8_STRING (string_desc_p, cesu8_str_p, cesu8_str_size);
1204  ecma_length_t cesu8_str_length = ecma_string_get_length (string_desc_p);
1205
1206  if (cesu8_str_length == cesu8_str_size)
1207  {
1208    cesu8_str_p += start_pos;
1209    size = end_pos - start_pos;
1210
1211    if (size > buffer_size)
1212    {
1213      size = buffer_size;
1214    }
1215
1216    memcpy (buffer_p, cesu8_str_p, size);
1217  }
1218  else
1219  {
1220    const lit_utf8_byte_t *cesu8_end_pos = cesu8_str_p + cesu8_str_size;
1221    end_pos -= start_pos;
1222
1223    while (start_pos--)
1224    {
1225      ecma_char_t ch;
1226      lit_utf8_size_t code_unit_size = lit_read_code_unit_from_utf8 (cesu8_str_p, &ch);
1227
1228      cesu8_str_p += code_unit_size;
1229      if ((cesu8_str_p != cesu8_end_pos) && lit_is_code_point_utf16_high_surrogate (ch))
1230      {
1231        ecma_char_t next_ch;
1232        lit_utf8_size_t next_ch_size = lit_read_code_unit_from_utf8 (cesu8_str_p, &next_ch);
1233        if (lit_is_code_point_utf16_low_surrogate (next_ch))
1234        {
1235          JERRY_ASSERT (code_unit_size == next_ch_size);
1236          cesu8_str_p += code_unit_size;
1237        }
1238      }
1239    }
1240
1241    const lit_utf8_byte_t *cesu8_pos = cesu8_str_p;
1242
1243    lit_utf8_byte_t *utf8_pos = buffer_p;
1244    lit_utf8_byte_t *utf8_end_pos = buffer_p + buffer_size;
1245
1246    while (end_pos--)
1247    {
1248      ecma_char_t ch;
1249      lit_utf8_size_t code_unit_size = lit_read_code_unit_from_utf8 (cesu8_pos, &ch);
1250
1251      if ((size + code_unit_size) > buffer_size)
1252      {
1253        break;
1254      }
1255
1256      if (((cesu8_pos + code_unit_size) != cesu8_end_pos) && lit_is_code_point_utf16_high_surrogate (ch))
1257      {
1258        ecma_char_t next_ch;
1259        lit_utf8_size_t next_ch_size = lit_read_code_unit_from_utf8 (cesu8_pos + code_unit_size, &next_ch);
1260
1261        if (lit_is_code_point_utf16_low_surrogate (next_ch))
1262        {
1263          JERRY_ASSERT (code_unit_size == next_ch_size);
1264
1265          if ((size + code_unit_size + 1) > buffer_size)
1266          {
1267            break;
1268          }
1269
1270          cesu8_pos += next_ch_size;
1271
1272          lit_code_point_t code_point = lit_convert_surrogate_pair_to_code_point (ch, next_ch);
1273          lit_code_point_to_utf8 (code_point, utf8_pos);
1274          size += (code_unit_size + 1);
1275        }
1276        else
1277        {
1278          memcpy (utf8_pos, cesu8_pos, code_unit_size);
1279          size += code_unit_size;
1280        }
1281      }
1282      else
1283      {
1284        memcpy (utf8_pos, cesu8_pos, code_unit_size);
1285        size += code_unit_size;
1286      }
1287
1288      utf8_pos = buffer_p + size;
1289      cesu8_pos += code_unit_size;
1290    }
1291
1292    JERRY_ASSERT (utf8_pos <= utf8_end_pos);
1293  }
1294
1295  ECMA_FINALIZE_UTF8_STRING (cesu8_str_p, cesu8_str_size);
1296  JERRY_ASSERT (size <= buffer_size);
1297
1298  return size;
1299} /* ecma_substring_copy_to_utf8_buffer */
1300
1301/**
1302 * Convert ecma-string's contents to a cesu-8 string and put it to the buffer.
1303 * It is the caller's responsibility to make sure that the string fits in the buffer.
1304 * Check if the size of the string is equal with the size of the buffer.
1305 */
1306inline void JERRY_ATTR_ALWAYS_INLINE
1307ecma_string_to_utf8_bytes (const ecma_string_t *string_desc_p, /**< ecma-string descriptor */
1308                           lit_utf8_byte_t *buffer_p, /**< destination buffer pointer
1309                                                       * (can be NULL if buffer_size == 0) */
1310                           lit_utf8_size_t buffer_size) /**< size of buffer */
1311{
1312  const lit_utf8_size_t size = ecma_string_copy_to_cesu8_buffer (string_desc_p, buffer_p, buffer_size);
1313  JERRY_ASSERT (size == buffer_size);
1314} /* ecma_string_to_utf8_bytes */
1315
1316/**
1317 * Get size of the uint32 number stored locally in the string's descriptor
1318 *
1319 * Note: the represented number size and length are equal
1320 *
1321 * @return size in bytes
1322 */
1323static inline ecma_length_t JERRY_ATTR_ALWAYS_INLINE
1324ecma_string_get_uint32_size (const uint32_t uint32_number) /**< number in the string-descriptor */
1325{
1326  uint32_t prev_number = 1;
1327  uint32_t next_number = 100;
1328  ecma_length_t size = 1;
1329
1330  const uint32_t max_size = 9;
1331
1332  while (size < max_size && uint32_number >= next_number)
1333  {
1334    prev_number = next_number;
1335    next_number *= 100;
1336    size += 2;
1337  }
1338
1339  if (uint32_number >= prev_number * 10)
1340  {
1341    size++;
1342  }
1343
1344  return size;
1345} /* ecma_string_get_uint32_size */
1346
1347/**
1348 * Checks whether the given string is a sequence of ascii characters.
1349 */
1350#define ECMA_STRING_IS_ASCII(char_p, size) ((size) == lit_utf8_string_length ((char_p), (size)))
1351
1352/**
1353 * Returns with the cesu8 character array of a string.
1354 *
1355 * Note:
1356 *   - This function returns with a newly allocated buffer for uint32 strings,
1357 *     which must be freed if the optional uint32_buff_p parameter is NULL.
1358 *   - The ASCII check only happens if the flags parameter gets
1359 *     'ECMA_STRING_FLAG_IS_ASCII' as an input.
1360 *
1361 * @return start of cesu8 characters
1362 */
1363const lit_utf8_byte_t *
1364ecma_string_get_chars (const ecma_string_t *string_p, /**< ecma-string */
1365                       lit_utf8_size_t *size_p, /**< [out] size of the ecma string */
1366                       lit_utf8_size_t *length_p, /**< [out] optional argument. If the pointer is not NULL the pointed
1367                                                   *    memory area is filled with the length of the ecma string */
1368                       lit_utf8_byte_t *uint32_buff_p, /**< [out] optional argument. If the pointer is not NULL the
1369                                                        *    pointed memory area is filled with the string converted
1370                                                        *    uint32 string descriptor */
1371                       uint8_t *flags_p) /**< [in,out] any combination of ecma_string_flag_t bits */
1372{
1373  ecma_length_t length;
1374  lit_utf8_size_t size;
1375  const lit_utf8_byte_t *result_p;
1376
1377  if (ECMA_IS_DIRECT_STRING (string_p))
1378  {
1379    *flags_p |= ECMA_STRING_FLAG_REHASH_NEEDED;
1380
1381    switch (ECMA_GET_DIRECT_STRING_TYPE (string_p))
1382    {
1383      case ECMA_DIRECT_STRING_MAGIC:
1384      {
1385        uint32_t id = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
1386
1387        if (id >= LIT_MAGIC_STRING__COUNT)
1388        {
1389          id -= LIT_MAGIC_STRING__COUNT;
1390          size = lit_get_magic_string_ex_size (id);
1391          result_p = lit_get_magic_string_ex_utf8 (id);
1392          length = 0;
1393
1394          if (JERRY_UNLIKELY (*flags_p & ECMA_STRING_FLAG_IS_ASCII))
1395          {
1396            length = lit_utf8_string_length (result_p, size);
1397          }
1398        }
1399        else
1400        {
1401          size = lit_get_magic_string_size (id);
1402          length = size;
1403
1404          result_p = lit_get_magic_string_utf8 (id);
1405
1406          /* All magic strings must be ascii strings. */
1407          JERRY_ASSERT (ECMA_STRING_IS_ASCII (result_p, size));
1408        }
1409        break;
1410      }
1411      default:
1412      {
1413        JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_UINT);
1414        uint32_t uint32_number = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
1415        size = (lit_utf8_size_t) ecma_string_get_uint32_size (uint32_number);
1416
1417        if (uint32_buff_p != NULL)
1418        {
1419          result_p = uint32_buff_p;
1420        }
1421        else
1422        {
1423          result_p = (const lit_utf8_byte_t *) jmem_heap_alloc_block (size);
1424          *flags_p |= ECMA_STRING_FLAG_MUST_BE_FREED;
1425        }
1426
1427        length = ecma_uint32_to_utf8_string (uint32_number, (lit_utf8_byte_t *) result_p, size);
1428
1429        JERRY_ASSERT (length == size);
1430        *flags_p |= ECMA_STRING_FLAG_IS_UINT32;
1431        break;
1432      }
1433    }
1434  }
1435  else
1436  {
1437    JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE);
1438
1439    switch (ECMA_STRING_GET_CONTAINER (string_p))
1440    {
1441      case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING:
1442      {
1443        ecma_utf8_string_t *utf8_string_desc_p = (ecma_utf8_string_t *) string_p;
1444        size = utf8_string_desc_p->size;
1445        length = utf8_string_desc_p->length;
1446        result_p = ECMA_UTF8_STRING_GET_BUFFER (utf8_string_desc_p);
1447        break;
1448      }
1449      case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING:
1450      {
1451        ecma_long_utf8_string_t *long_utf8_string_desc_p = (ecma_long_utf8_string_t *) string_p;
1452        size = long_utf8_string_desc_p->size;
1453        length = long_utf8_string_desc_p->length;
1454        result_p = ECMA_LONG_UTF8_STRING_GET_BUFFER (long_utf8_string_desc_p);
1455        break;
1456      }
1457      case ECMA_STRING_CONTAINER_HEAP_ASCII_STRING:
1458      {
1459        ecma_ascii_string_t *ascii_string_desc_p = (ecma_ascii_string_t *) string_p;
1460        size = ascii_string_desc_p->size;
1461        length = ascii_string_desc_p->size;
1462        result_p = ECMA_ASCII_STRING_GET_BUFFER (ascii_string_desc_p);
1463        break;
1464      }
1465      case ECMA_STRING_CONTAINER_UINT32_IN_DESC:
1466      {
1467        size = (lit_utf8_size_t) ecma_string_get_uint32_size (string_p->u.uint32_number);
1468
1469        if (uint32_buff_p != NULL)
1470        {
1471          result_p = uint32_buff_p;
1472        }
1473        else
1474        {
1475          result_p = (const lit_utf8_byte_t *) jmem_heap_alloc_block (size);
1476          *flags_p |= ECMA_STRING_FLAG_MUST_BE_FREED;
1477        }
1478
1479        length = ecma_uint32_to_utf8_string (string_p->u.uint32_number, (lit_utf8_byte_t *) result_p, size);
1480
1481        JERRY_ASSERT (length == size);
1482        *flags_p |= ECMA_STRING_FLAG_IS_UINT32 | ECMA_STRING_FLAG_REHASH_NEEDED;
1483        break;
1484
1485      }
1486      default:
1487      {
1488        JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);
1489
1490        lit_magic_string_ex_id_t id = LIT_MAGIC_STRING__COUNT - string_p->u.magic_string_ex_id;
1491        size = lit_get_magic_string_ex_size (id);
1492        length = 0;
1493
1494        if (JERRY_UNLIKELY (*flags_p & ECMA_STRING_FLAG_IS_ASCII))
1495        {
1496          length = lit_utf8_string_length (lit_get_magic_string_ex_utf8 (id), size);
1497        }
1498
1499        result_p = lit_get_magic_string_ex_utf8 (id);
1500        *flags_p |= ECMA_STRING_FLAG_REHASH_NEEDED;
1501        break;
1502      }
1503    }
1504  }
1505
1506  *size_p = size;
1507  if (length_p != NULL)
1508  {
1509    *length_p = length;
1510  }
1511
1512  if ((*flags_p & ECMA_STRING_FLAG_IS_ASCII)
1513      && length != size)
1514  {
1515    *flags_p = (uint8_t) (*flags_p & (uint8_t) ~ECMA_STRING_FLAG_IS_ASCII);
1516  }
1517
1518  return result_p;
1519} /* ecma_string_get_chars */
1520
1521/**
1522 * Checks whether the string equals to the magic string id.
1523 *
1524 * @return true - if the string equals to the magic string id
1525 *         false - otherwise
1526 */
1527inline bool JERRY_ATTR_ALWAYS_INLINE
1528ecma_compare_ecma_string_to_magic_id (const ecma_string_t *string_p, /**< property name */
1529                                      lit_magic_string_id_t id) /**< magic string id */
1530{
1531  return (string_p == ecma_get_magic_string (id));
1532} /* ecma_compare_ecma_string_to_magic_id */
1533
1534/**
1535 * Checks whether ecma string is empty or not
1536 *
1537 * @return true - if the string is an empty string
1538 *         false - otherwise
1539 */
1540inline bool JERRY_ATTR_ALWAYS_INLINE
1541ecma_string_is_empty (const ecma_string_t *string_p) /**< ecma-string */
1542{
1543  return ecma_compare_ecma_string_to_magic_id (string_p, LIT_MAGIC_STRING__EMPTY);
1544} /* ecma_string_is_empty */
1545
1546/**
1547 * Checks whether the string equals to "length".
1548 *
1549 * @return true - if the string equals to "length"
1550 *         false - otherwise
1551 */
1552inline bool JERRY_ATTR_ALWAYS_INLINE
1553ecma_string_is_length (const ecma_string_t *string_p) /**< property name */
1554{
1555  return ecma_compare_ecma_string_to_magic_id (string_p, LIT_MAGIC_STRING_LENGTH);
1556} /* ecma_string_is_length */
1557
1558/**
1559 * Converts a property name into a string
1560 *
1561 * @return pointer to the converted ecma string
1562 */
1563static inline ecma_string_t * JERRY_ATTR_ALWAYS_INLINE
1564ecma_property_to_string (ecma_property_t property, /**< property name type */
1565                         jmem_cpointer_t prop_name_cp) /**< property name compressed pointer */
1566{
1567  uintptr_t property_string = ((uintptr_t) (property)) & (0x3 << ECMA_PROPERTY_NAME_TYPE_SHIFT);
1568  property_string = (property_string >> ECMA_STRING_TYPE_CONVERSION_SHIFT) | ECMA_TYPE_DIRECT_STRING;
1569  return (ecma_string_t *) (property_string | (((uintptr_t) prop_name_cp) << ECMA_DIRECT_STRING_SHIFT));
1570} /* ecma_property_to_string */
1571
1572/**
1573 * Converts a string into a property name
1574 *
1575 * @return the compressed pointer part of the name
1576 */
1577inline jmem_cpointer_t JERRY_ATTR_ALWAYS_INLINE
1578ecma_string_to_property_name (ecma_string_t *prop_name_p, /**< property name */
1579                              ecma_property_t *name_type_p) /**< [out] property name type */
1580{
1581  if (ECMA_IS_DIRECT_STRING (prop_name_p))
1582  {
1583    *name_type_p = (ecma_property_t) ECMA_DIRECT_STRING_TYPE_TO_PROP_NAME_TYPE (prop_name_p);
1584    return (jmem_cpointer_t) ECMA_GET_DIRECT_STRING_VALUE (prop_name_p);
1585  }
1586
1587  *name_type_p = ECMA_DIRECT_STRING_PTR << ECMA_PROPERTY_NAME_TYPE_SHIFT;
1588
1589  ecma_ref_ecma_string (prop_name_p);
1590
1591  jmem_cpointer_t prop_name_cp;
1592  ECMA_SET_NON_NULL_POINTER (prop_name_cp, prop_name_p);
1593  return prop_name_cp;
1594} /* ecma_string_to_property_name */
1595
1596/**
1597 * Converts a property name into a string
1598 *
1599 * @return the string pointer
1600 *         string must be released with ecma_deref_ecma_string
1601 */
1602ecma_string_t *
1603ecma_string_from_property_name (ecma_property_t property, /**< property name type */
1604                                jmem_cpointer_t prop_name_cp) /**< property name compressed pointer */
1605{
1606  if (ECMA_PROPERTY_GET_NAME_TYPE (property) != ECMA_DIRECT_STRING_PTR)
1607  {
1608    return ecma_property_to_string (property, prop_name_cp);
1609  }
1610
1611  ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_name_cp);
1612  ecma_ref_ecma_string (prop_name_p);
1613  return prop_name_p;
1614} /* ecma_string_from_property_name */
1615
1616/**
1617 * Get hash code of property name
1618 *
1619 * @return hash code of property name
1620 */
1621inline lit_string_hash_t JERRY_ATTR_ALWAYS_INLINE
1622ecma_string_get_property_name_hash (ecma_property_t property, /**< property name type */
1623                                    jmem_cpointer_t prop_name_cp) /**< property name compressed pointer */
1624{
1625  if (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_DIRECT_STRING_PTR)
1626  {
1627    ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_name_cp);
1628    return prop_name_p->u.hash;
1629  }
1630
1631  return (lit_string_hash_t) prop_name_cp;
1632} /* ecma_string_get_property_name_hash */
1633
1634/**
1635 * Check if property name is array index.
1636 *
1637 * @return ECMA_STRING_NOT_ARRAY_INDEX if string is not array index
1638 *         the array index otherwise
1639 */
1640uint32_t
1641ecma_string_get_property_index (ecma_property_t property, /**< property name type */
1642                                jmem_cpointer_t prop_name_cp) /**< property name compressed pointer */
1643{
1644  switch (ECMA_PROPERTY_GET_NAME_TYPE (property))
1645  {
1646    case ECMA_DIRECT_STRING_UINT:
1647    {
1648      return (uint32_t) prop_name_cp;
1649    }
1650    case ECMA_DIRECT_STRING_PTR:
1651    {
1652      ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_name_cp);
1653      return ecma_string_get_array_index (prop_name_p);
1654    }
1655    default:
1656    {
1657      return ECMA_STRING_NOT_ARRAY_INDEX;
1658    }
1659  }
1660} /* ecma_string_get_property_index */
1661
1662/**
1663 * Compare a property name to a string
1664 *
1665 * @return true if they are equals
1666 *         false otherwise
1667 */
1668inline bool JERRY_ATTR_ALWAYS_INLINE
1669ecma_string_compare_to_property_name (ecma_property_t property, /**< property name type */
1670                                      jmem_cpointer_t prop_name_cp, /**< property name compressed pointer */
1671                                      const ecma_string_t *string_p) /**< other string */
1672{
1673  if (ECMA_PROPERTY_GET_NAME_TYPE (property) != ECMA_DIRECT_STRING_PTR)
1674  {
1675    return ecma_property_to_string (property, prop_name_cp) == string_p;
1676  }
1677
1678  if (ECMA_IS_DIRECT_STRING (string_p))
1679  {
1680    return false;
1681  }
1682
1683  ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_name_cp);
1684  return ecma_compare_ecma_non_direct_strings (prop_name_p, string_p);
1685} /* ecma_string_compare_to_property_name */
1686
1687/**
1688 * Long path part of ecma-string to ecma-string comparison routine
1689 *
1690 * See also:
1691 *          ecma_compare_ecma_strings
1692 *
1693 * @return true - if strings are equal;
1694 *         false - otherwise
1695 */
1696static bool JERRY_ATTR_NOINLINE
1697ecma_compare_ecma_strings_longpath (const ecma_string_t *string1_p, /**< ecma-string */
1698                                    const ecma_string_t *string2_p) /**< ecma-string */
1699{
1700  JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_GET_CONTAINER (string2_p));
1701
1702  const lit_utf8_byte_t *utf8_string1_p, *utf8_string2_p;
1703  lit_utf8_size_t utf8_string1_size, utf8_string2_size;
1704
1705  if (JERRY_LIKELY (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_HEAP_UTF8_STRING))
1706  {
1707    utf8_string1_p = ECMA_UTF8_STRING_GET_BUFFER (string1_p);
1708    utf8_string1_size = ((ecma_utf8_string_t *) string1_p)->size;
1709    utf8_string2_p = ECMA_UTF8_STRING_GET_BUFFER (string2_p);
1710    utf8_string2_size = ((ecma_utf8_string_t *) string2_p)->size;
1711
1712  }
1713  else if (ECMA_STRING_GET_CONTAINER(string1_p) == ECMA_STRING_CONTAINER_HEAP_ASCII_STRING)
1714  {
1715    utf8_string1_p = ECMA_ASCII_STRING_GET_BUFFER (string1_p);
1716    utf8_string1_size = ((ecma_ascii_string_t *) string1_p)->size;
1717    utf8_string2_p = ECMA_ASCII_STRING_GET_BUFFER (string2_p);
1718    utf8_string2_size = ((ecma_ascii_string_t *) string2_p)->size;
1719  }
1720  else
1721  {
1722    JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING);
1723
1724    utf8_string1_p = ECMA_LONG_UTF8_STRING_GET_BUFFER (string1_p);
1725    utf8_string1_size = ((ecma_long_utf8_string_t *) string1_p)->size;
1726    utf8_string2_p = ECMA_LONG_UTF8_STRING_GET_BUFFER (string2_p);
1727    utf8_string2_size = ((ecma_long_utf8_string_t *) string2_p)->size;
1728  }
1729
1730  if (utf8_string1_size != utf8_string2_size)
1731  {
1732    return false;
1733  }
1734
1735  return !memcmp ((char *) utf8_string1_p, (char *) utf8_string2_p, utf8_string1_size);
1736} /* ecma_compare_ecma_strings_longpath */
1737
1738/**
1739 * Compare two ecma-strings
1740 *
1741 * @return true - if strings are equal;
1742 *         false - otherwise
1743 */
1744extern inline bool JERRY_ATTR_ALWAYS_INLINE
1745ecma_compare_ecma_strings (const ecma_string_t *string1_p, /**< ecma-string */
1746                           const ecma_string_t *string2_p) /**< ecma-string */
1747{
1748  JERRY_ASSERT (string1_p != NULL && string2_p != NULL);
1749
1750  /* Fast paths first. */
1751  if (string1_p == string2_p)
1752  {
1753    return true;
1754  }
1755
1756  /* Either string is direct, return with false. */
1757  if (ECMA_IS_DIRECT_STRING (((uintptr_t) string1_p) | ((uintptr_t) string2_p)))
1758  {
1759    return false;
1760  }
1761
1762  if (string1_p->u.hash != string2_p->u.hash)
1763  {
1764    return false;
1765  }
1766
1767  ecma_string_container_t string1_container = ECMA_STRING_GET_CONTAINER (string1_p);
1768
1769  if (string1_container != ECMA_STRING_GET_CONTAINER (string2_p))
1770  {
1771    return false;
1772  }
1773
1774  if (string1_container == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
1775  {
1776    return true;
1777  }
1778
1779#if ENABLED (JERRY_ES2015)
1780  if (string1_container == ECMA_STRING_CONTAINER_SYMBOL)
1781  {
1782    return false;
1783  }
1784#endif /* ENABLED (JERRY_ES2015) */
1785
1786  return ecma_compare_ecma_strings_longpath (string1_p, string2_p);
1787} /* ecma_compare_ecma_strings */
1788
1789static bool JERRY_ATTR_NOINLINE
1790ecma_compare_ecma_strings_longpath_with_literal (const ecma_string_t *string1_p, /**< ecma_string */
1791                                       const ecma_string_t *string2_p,
1792                                       const lit_utf8_byte_t *chars_p) /**< ecma_string */
1793{
1794  JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_GET_CONTAINER (string2_p));
1795
1796  const lit_utf8_byte_t *utf8_string2_p;
1797  lit_utf8_size_t utf8_string1_size,utf8_string2_size;
1798
1799  if(JERRY_LIKELY (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_HEAP_UTF8_STRING))
1800  {
1801     utf8_string1_size = ((ecma_utf8_string_t *) string1_p)->size;
1802     utf8_string2_p = ECMA_UTF8_STRING_GET_BUFFER (string2_p);
1803     utf8_string2_size = ((ecma_utf8_string_t *) string2_p)->size;
1804
1805  }
1806  else if (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_HEAP_ASCII_STRING)
1807  {
1808    utf8_string1_size = ((ecma_ascii_string_t *) string1_p)->size;
1809    utf8_string2_p = ECMA_ASCII_STRING_GET_BUFFER (string2_p);
1810    utf8_string2_size = ((ecma_ascii_string_t *) string2_p)->size;
1811  }
1812  else
1813  {
1814      JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING);
1815
1816    utf8_string1_size = ((ecma_long_utf8_string_t *) string1_p)->size;
1817    utf8_string2_p = ECMA_LONG_UTF8_STRING_GET_BUFFER (string2_p);
1818    utf8_string2_size = ((ecma_long_utf8_string_t *) string2_p)->size;
1819  }
1820
1821  if (utf8_string1_size != utf8_string2_size)
1822  {
1823      return false;
1824  }
1825
1826  return !memcmp ((char *) chars_p, (char *) utf8_string2_p, utf8_string1_size);
1827}  /* ecma_compare_ecma_strings_longpath */
1828
1829extern inline bool JERRY_ATTR_ALWAYS_INLINE
1830ecma_compare_ecma_strings_with_literal (const ecma_string_t *string1_p, /**< ecma-string */
1831                          const ecma_string_t *string2_p,
1832                          const lit_utf8_byte_t *chars_p) /**< ecma-string */
1833{
1834   JERRY_ASSERT (string1_p != NULL && string2_p != NULL);
1835
1836   /* Fast paths first. */
1837   if  (string1_p == string2_p)
1838   {
1839       return true;
1840   }
1841
1842   /* Either string is direct, return with false. */
1843   if (ECMA_IS_DIRECT_STRING (((uintptr_t) string1_p) | ((uintptr_t) string2_p)))
1844   {
1845      return false;
1846   }
1847
1848   if (string1_p->u.hash != string2_p->u.hash)
1849   {
1850      return false;
1851   }
1852
1853   ecma_string_container_t string1_container = ECMA_STRING_GET_CONTAINER (string1_p);
1854
1855   if (string1_container != ECMA_STRING_GET_CONTAINER (string2_p))
1856   {
1857      return false;
1858   }
1859
1860   if (string1_container == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
1861   {
1862      return true;
1863   }
1864
1865#if ENABLED (JERRY_ES2015)
1866  if (string1_container == ECMA_STRING_CONTAINER_SYMBOL)
1867  {
1868     return false;
1869  }
1870#endif /* ENABLED (JERRY_ES2015)  */
1871
1872  return ecma_compare_ecma_strings_longpath_with_literal (string1_p, string2_p, chars_p);
1873}  /* ecma_compare_ecma_strings */
1874
1875/**
1876 * Compare two non-direct ecma-strings
1877 *
1878 * @return true - if strings are equal;
1879 *         false - otherwise
1880 */
1881inline bool JERRY_ATTR_ALWAYS_INLINE
1882ecma_compare_ecma_non_direct_strings (const ecma_string_t *string1_p, /**< ecma-string */
1883                                      const ecma_string_t *string2_p) /**< ecma-string */
1884{
1885  JERRY_ASSERT (string1_p != NULL && string2_p != NULL);
1886  JERRY_ASSERT (!ECMA_IS_DIRECT_STRING (string1_p) && !ECMA_IS_DIRECT_STRING (string2_p));
1887
1888  /* Fast paths first. */
1889  if (string1_p == string2_p)
1890  {
1891    return true;
1892  }
1893
1894  if (string1_p->u.hash != string2_p->u.hash)
1895  {
1896    return false;
1897  }
1898
1899  ecma_string_container_t string1_container = ECMA_STRING_GET_CONTAINER (string1_p);
1900
1901  if (string1_container != ECMA_STRING_GET_CONTAINER (string2_p))
1902  {
1903    return false;
1904  }
1905
1906  if (string1_container == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
1907  {
1908    return true;
1909  }
1910
1911#if ENABLED (JERRY_ES2015)
1912  if (string1_container == ECMA_STRING_CONTAINER_SYMBOL)
1913  {
1914    return false;
1915  }
1916#endif /* ENABLED (JERRY_ES2015) */
1917
1918  return ecma_compare_ecma_strings_longpath (string1_p, string2_p);
1919} /* ecma_compare_ecma_non_direct_strings */
1920
1921/**
1922 * Relational compare of ecma-strings.
1923 *
1924 * First string is less than second string if:
1925 *  - strings are not equal;
1926 *  - first string is prefix of second or is lexicographically less than second.
1927 *
1928 * @return true - if first string is less than second string,
1929 *         false - otherwise
1930 */
1931bool
1932ecma_compare_ecma_strings_relational (const ecma_string_t *string1_p, /**< ecma-string */
1933                                      const ecma_string_t *string2_p) /**< ecma-string */
1934{
1935  if (ecma_compare_ecma_strings (string1_p,
1936                                 string2_p))
1937  {
1938    return false;
1939  }
1940
1941  const lit_utf8_byte_t *utf8_string1_p, *utf8_string2_p;
1942  lit_utf8_size_t utf8_string1_size, utf8_string2_size;
1943
1944  lit_utf8_byte_t uint32_to_string_buffer1[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32];
1945  lit_utf8_byte_t uint32_to_string_buffer2[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32];
1946
1947  if (ECMA_IS_DIRECT_STRING (string1_p))
1948  {
1949    if (ECMA_GET_DIRECT_STRING_TYPE (string1_p) != ECMA_DIRECT_STRING_UINT)
1950    {
1951      utf8_string1_p = ecma_string_get_chars_fast (string1_p, &utf8_string1_size);
1952    }
1953    else
1954    {
1955      utf8_string1_size = ecma_uint32_to_utf8_string ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string1_p),
1956                                                      uint32_to_string_buffer1,
1957                                                      ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
1958      utf8_string1_p = uint32_to_string_buffer1;
1959    }
1960  }
1961  else
1962  {
1963    JERRY_ASSERT (string1_p->refs_and_container >= ECMA_STRING_REF_ONE);
1964
1965    if (ECMA_STRING_GET_CONTAINER (string1_p) != ECMA_STRING_CONTAINER_UINT32_IN_DESC)
1966    {
1967      utf8_string1_p = ecma_string_get_chars_fast (string1_p, &utf8_string1_size);
1968    }
1969    else
1970    {
1971      utf8_string1_size = ecma_uint32_to_utf8_string (string1_p->u.uint32_number,
1972                                                      uint32_to_string_buffer1,
1973                                                      ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
1974      utf8_string1_p = uint32_to_string_buffer1;
1975    }
1976  }
1977
1978  if (ECMA_IS_DIRECT_STRING (string2_p))
1979  {
1980    if (ECMA_GET_DIRECT_STRING_TYPE (string2_p) != ECMA_DIRECT_STRING_UINT)
1981    {
1982      utf8_string2_p = ecma_string_get_chars_fast (string2_p, &utf8_string2_size);
1983    }
1984    else
1985    {
1986      utf8_string2_size = ecma_uint32_to_utf8_string ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string2_p),
1987                                                      uint32_to_string_buffer2,
1988                                                      ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
1989      utf8_string2_p = uint32_to_string_buffer2;
1990    }
1991  }
1992  else
1993  {
1994    JERRY_ASSERT (string2_p->refs_and_container >= ECMA_STRING_REF_ONE);
1995
1996    if (ECMA_STRING_GET_CONTAINER (string2_p) != ECMA_STRING_CONTAINER_UINT32_IN_DESC)
1997    {
1998      utf8_string2_p = ecma_string_get_chars_fast (string2_p, &utf8_string2_size);
1999    }
2000    else
2001    {
2002      utf8_string2_size = ecma_uint32_to_utf8_string (string2_p->u.uint32_number,
2003                                                      uint32_to_string_buffer2,
2004                                                      ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
2005      utf8_string2_p = uint32_to_string_buffer2;
2006    }
2007  }
2008
2009  return lit_compare_utf8_strings_relational (utf8_string1_p,
2010                                              utf8_string1_size,
2011                                              utf8_string2_p,
2012                                              utf8_string2_size);
2013} /* ecma_compare_ecma_strings_relational */
2014
2015/**
2016 * Special value to represent that no size is available.
2017 */
2018#define ECMA_STRING_NO_ASCII_SIZE 0xffffffff
2019
2020/**
2021 * Return the size of uint32 and magic strings.
2022 * The length of these strings are equal to their size.
2023 *
2024 * @return number of characters in the string
2025 */
2026static ecma_length_t
2027ecma_string_get_ascii_size (const ecma_string_t *string_p) /**< ecma-string */
2028{
2029  if (ECMA_IS_DIRECT_STRING (string_p))
2030  {
2031    switch (ECMA_GET_DIRECT_STRING_TYPE (string_p))
2032    {
2033      case ECMA_DIRECT_STRING_MAGIC:
2034      {
2035        uint32_t id = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
2036
2037        if (id >= LIT_MAGIC_STRING__COUNT)
2038        {
2039          return ECMA_STRING_NO_ASCII_SIZE;
2040        }
2041
2042        JERRY_ASSERT (ECMA_STRING_IS_ASCII (lit_get_magic_string_utf8 (id),
2043                                            lit_get_magic_string_size (id)));
2044
2045        return lit_get_magic_string_size (id);
2046      }
2047      default:
2048      {
2049        JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_UINT);
2050        uint32_t uint32_number = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
2051        return ecma_string_get_uint32_size (uint32_number);
2052      }
2053    }
2054  }
2055
2056  JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE);
2057
2058  if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
2059  {
2060    return ecma_string_get_uint32_size (string_p->u.uint32_number);
2061  }
2062  else if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_HEAP_ASCII_STRING)
2063  {
2064    return ((ecma_ascii_string_t *) string_p)->size;
2065  }
2066
2067  return ECMA_STRING_NO_ASCII_SIZE;
2068} /* ecma_string_get_ascii_size */
2069
2070/**
2071 * Get length of ecma-string
2072 *
2073 * @return number of characters in the string
2074 */
2075ecma_length_t
2076ecma_string_get_length (const ecma_string_t *string_p) /**< ecma-string */
2077{
2078  ecma_length_t length = ecma_string_get_ascii_size (string_p);
2079
2080  if (length != ECMA_STRING_NO_ASCII_SIZE)
2081  {
2082    return length;
2083  }
2084
2085  if (ECMA_IS_DIRECT_STRING (string_p))
2086  {
2087    JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC);
2088    JERRY_ASSERT ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p) >= LIT_MAGIC_STRING__COUNT);
2089
2090    uint32_t id = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p) - LIT_MAGIC_STRING__COUNT;
2091    return lit_utf8_string_length (lit_get_magic_string_ex_utf8 (id),
2092                                   lit_get_magic_string_ex_size (id));
2093  }
2094
2095  if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_HEAP_UTF8_STRING)
2096  {
2097    return (ecma_length_t) (((ecma_utf8_string_t *) string_p)->length);
2098  }
2099
2100  if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING)
2101  {
2102    return (ecma_length_t) (((ecma_long_utf8_string_t *) string_p)->length);
2103  }
2104
2105  JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);
2106
2107  lit_magic_string_ex_id_t id = LIT_MAGIC_STRING__COUNT - string_p->u.magic_string_ex_id;
2108  return lit_utf8_string_length (lit_get_magic_string_ex_utf8 (id),
2109                                 lit_get_magic_string_ex_size (id));
2110} /* ecma_string_get_length */
2111
2112/**
2113 * Get length of UTF-8 encoded string length from ecma-string
2114 *
2115 * @return number of characters in the UTF-8 encoded string
2116 */
2117ecma_length_t
2118ecma_string_get_utf8_length (const ecma_string_t *string_p) /**< ecma-string */
2119{
2120  ecma_length_t length = ecma_string_get_ascii_size (string_p);
2121
2122  if (length != ECMA_STRING_NO_ASCII_SIZE)
2123  {
2124    return length;
2125  }
2126
2127  if (ECMA_IS_DIRECT_STRING (string_p))
2128  {
2129    JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC);
2130    JERRY_ASSERT ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p) >= LIT_MAGIC_STRING__COUNT);
2131
2132    uint32_t id = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p) - LIT_MAGIC_STRING__COUNT;
2133    return lit_get_utf8_length_of_cesu8_string (lit_get_magic_string_ex_utf8 (id),
2134                                                lit_get_magic_string_ex_size (id));
2135  }
2136
2137  if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_HEAP_UTF8_STRING)
2138  {
2139    ecma_utf8_string_t *utf8_string_p = (ecma_utf8_string_t *) string_p;
2140
2141    if (utf8_string_p->size == utf8_string_p->length)
2142    {
2143      return (ecma_length_t) (utf8_string_p->length);
2144    }
2145
2146    return lit_get_utf8_length_of_cesu8_string (ECMA_UTF8_STRING_GET_BUFFER (string_p), utf8_string_p->size);
2147  }
2148
2149  if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING)
2150  {
2151    ecma_long_utf8_string_t *long_utf8_string_p = (ecma_long_utf8_string_t *) string_p;
2152
2153    if (long_utf8_string_p->size == long_utf8_string_p->length)
2154    {
2155      return (ecma_length_t) (long_utf8_string_p->length);
2156    }
2157
2158    return lit_get_utf8_length_of_cesu8_string (ECMA_LONG_UTF8_STRING_GET_BUFFER (string_p),
2159                                                long_utf8_string_p->size);
2160  }
2161
2162  JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);
2163
2164  lit_magic_string_ex_id_t id = LIT_MAGIC_STRING__COUNT - string_p->u.magic_string_ex_id;
2165
2166  return lit_get_utf8_length_of_cesu8_string (lit_get_magic_string_ex_utf8 (id),
2167                                              lit_get_magic_string_ex_size (id));
2168} /* ecma_string_get_utf8_length */
2169
2170/**
2171 * Get size of ecma-string
2172 *
2173 * @return number of bytes in the buffer needed to represent the string
2174 */
2175lit_utf8_size_t
2176ecma_string_get_size (const ecma_string_t *string_p) /**< ecma-string */
2177{
2178  ecma_length_t length = ecma_string_get_ascii_size (string_p);
2179
2180  if (length != ECMA_STRING_NO_ASCII_SIZE)
2181  {
2182    return length;
2183  }
2184
2185  if (ECMA_IS_DIRECT_STRING (string_p))
2186  {
2187    JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC);
2188    JERRY_ASSERT ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p) >= LIT_MAGIC_STRING__COUNT);
2189
2190    return lit_get_magic_string_ex_size ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p) - LIT_MAGIC_STRING__COUNT);
2191  }
2192
2193  if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_HEAP_UTF8_STRING)
2194  {
2195    return (lit_utf8_size_t) (((ecma_utf8_string_t *) string_p)->size);
2196  }
2197
2198  if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING)
2199  {
2200    return (lit_utf8_size_t) (((ecma_long_utf8_string_t *) string_p)->size);
2201  }
2202
2203  JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);
2204
2205  return lit_get_magic_string_ex_size (LIT_MAGIC_STRING__COUNT - string_p->u.magic_string_ex_id);
2206} /* ecma_string_get_size */
2207
2208/**
2209 * Get the UTF-8 encoded string size from ecma-string
2210 *
2211 * @return number of bytes in the buffer needed to represent an UTF-8 encoded string
2212 */
2213lit_utf8_size_t
2214ecma_string_get_utf8_size (const ecma_string_t *string_p) /**< ecma-string */
2215{
2216  ecma_length_t length = ecma_string_get_ascii_size (string_p);
2217
2218  if (length != ECMA_STRING_NO_ASCII_SIZE)
2219  {
2220    return length;
2221  }
2222
2223  if (ECMA_IS_DIRECT_STRING (string_p))
2224  {
2225    JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC);
2226    JERRY_ASSERT ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p) >= LIT_MAGIC_STRING__COUNT);
2227
2228    uint32_t id = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p) - LIT_MAGIC_STRING__COUNT;
2229    return lit_get_utf8_size_of_cesu8_string (lit_get_magic_string_ex_utf8 (id),
2230                                              lit_get_magic_string_ex_size (id));
2231  }
2232
2233  if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_HEAP_UTF8_STRING)
2234  {
2235    ecma_utf8_string_t *utf8_string_p = (ecma_utf8_string_t *) string_p;
2236
2237    if (utf8_string_p->size == utf8_string_p->length)
2238    {
2239      return utf8_string_p->size;
2240    }
2241
2242    return lit_get_utf8_size_of_cesu8_string (ECMA_UTF8_STRING_GET_BUFFER (string_p), utf8_string_p->size);
2243  }
2244
2245  if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING)
2246  {
2247    ecma_long_utf8_string_t *long_utf8_string_p = (ecma_long_utf8_string_t *) string_p;
2248
2249    if (long_utf8_string_p->size == long_utf8_string_p->length)
2250    {
2251      return long_utf8_string_p->size;
2252    }
2253
2254    return lit_get_utf8_size_of_cesu8_string (ECMA_LONG_UTF8_STRING_GET_BUFFER (string_p),
2255                                              long_utf8_string_p->size);
2256  }
2257
2258  JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);
2259
2260  lit_magic_string_ex_id_t id = LIT_MAGIC_STRING__COUNT - string_p->u.magic_string_ex_id;
2261  return lit_get_utf8_size_of_cesu8_string (lit_get_magic_string_ex_utf8 (id),
2262                                            lit_get_magic_string_ex_size (id));
2263} /* ecma_string_get_utf8_size */
2264
2265/**
2266 * Get character from specified position in an external ecma-string.
2267 *
2268 * @return character value
2269 */
2270static ecma_char_t JERRY_ATTR_NOINLINE
2271ecma_external_string_get_char_at_pos (lit_utf8_size_t id, /**< id of the external magic string */
2272                                      ecma_length_t index) /**< index of character */
2273{
2274  id -= LIT_MAGIC_STRING__COUNT;
2275  const lit_utf8_byte_t *data_p = lit_get_magic_string_ex_utf8 (id);
2276  lit_utf8_size_t size = lit_get_magic_string_ex_size (id);
2277  lit_utf8_size_t length = lit_utf8_string_length (data_p, size);
2278
2279  if (JERRY_LIKELY (size == length))
2280  {
2281    return (ecma_char_t) data_p[index];
2282  }
2283
2284  return lit_utf8_string_code_unit_at (data_p, size, index);
2285} /* ecma_external_string_get_char_at_pos */
2286
2287/**
2288 * Get character from specified position in the ecma-string.
2289 *
2290 * @return character value
2291 */
2292ecma_char_t
2293ecma_string_get_char_at_pos (const ecma_string_t *string_p, /**< ecma-string */
2294                             ecma_length_t index) /**< index of character */
2295{
2296  JERRY_ASSERT (index < ecma_string_get_length (string_p));
2297
2298  lit_utf8_byte_t uint32_to_string_buffer[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32];
2299
2300  if (ECMA_IS_DIRECT_STRING (string_p))
2301  {
2302    switch (ECMA_GET_DIRECT_STRING_TYPE (string_p))
2303    {
2304      case ECMA_DIRECT_STRING_MAGIC:
2305      {
2306        uint32_t id = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
2307
2308        if (JERRY_LIKELY (id < LIT_MAGIC_STRING__COUNT))
2309        {
2310          /* All magic strings must be ascii strings. */
2311          const lit_utf8_byte_t *data_p = lit_get_magic_string_utf8 (id);
2312
2313          return (ecma_char_t) data_p[index];
2314        }
2315
2316        return ecma_external_string_get_char_at_pos (id, index);
2317      }
2318      default:
2319      {
2320        JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_UINT);
2321        uint32_t uint32_number = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
2322
2323        ecma_uint32_to_utf8_string (uint32_number, uint32_to_string_buffer, ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
2324
2325        return (ecma_char_t) uint32_to_string_buffer[index];
2326      }
2327    }
2328  }
2329
2330  JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE);
2331
2332  switch (ECMA_STRING_GET_CONTAINER (string_p))
2333  {
2334    case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING:
2335    {
2336      ecma_utf8_string_t *utf8_string_desc_p = (ecma_utf8_string_t *) string_p;
2337      lit_utf8_size_t size = utf8_string_desc_p->size;
2338      const lit_utf8_byte_t *data_p = ECMA_UTF8_STRING_GET_BUFFER (string_p);
2339
2340      if (JERRY_LIKELY (size == utf8_string_desc_p->length))
2341      {
2342        return (ecma_char_t) data_p[index];
2343      }
2344
2345      return lit_utf8_string_code_unit_at (data_p, size, index);
2346    }
2347    case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING:
2348    {
2349      ecma_long_utf8_string_t *long_utf8_string_desc_p = (ecma_long_utf8_string_t *) string_p;
2350      lit_utf8_size_t size = long_utf8_string_desc_p->size;
2351      const lit_utf8_byte_t *data_p = ECMA_LONG_UTF8_STRING_GET_BUFFER (string_p);
2352
2353      if (JERRY_LIKELY (size == long_utf8_string_desc_p->length))
2354      {
2355        return (ecma_char_t) data_p[index];
2356      }
2357
2358      return lit_utf8_string_code_unit_at (data_p, size, index);
2359    }
2360    case ECMA_STRING_CONTAINER_HEAP_ASCII_STRING:
2361    {
2362      const lit_utf8_byte_t *data_p = ECMA_ASCII_STRING_GET_BUFFER (string_p);
2363      return (ecma_char_t) data_p[index];
2364    }
2365    case ECMA_STRING_CONTAINER_UINT32_IN_DESC:
2366    {
2367      ecma_uint32_to_utf8_string (string_p->u.uint32_number,
2368                                  uint32_to_string_buffer,
2369                                  ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
2370
2371      return (ecma_char_t) uint32_to_string_buffer[index];
2372    }
2373    default:
2374    {
2375      JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);
2376      return ecma_external_string_get_char_at_pos (string_p->u.magic_string_ex_id, index);
2377    }
2378  }
2379} /* ecma_string_get_char_at_pos */
2380
2381/**
2382 * Check if passed string equals to one of magic strings
2383 * and if equal magic string was found, return it's id in 'out_id_p' argument.
2384 *
2385 * @return id - if magic string equal to passed string was found,
2386 *         LIT_MAGIC_STRING__COUNT - otherwise.
2387 */
2388lit_magic_string_id_t
2389ecma_get_string_magic (const ecma_string_t *string_p) /**< ecma-string */
2390{
2391  if (ECMA_IS_DIRECT_STRING_WITH_TYPE (string_p, ECMA_DIRECT_STRING_MAGIC))
2392  {
2393    uint32_t id = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
2394
2395    if (id < LIT_MAGIC_STRING__COUNT)
2396    {
2397      return (lit_magic_string_id_t) id;
2398    }
2399  }
2400
2401  return LIT_MAGIC_STRING__COUNT;
2402} /* ecma_get_string_magic */
2403
2404/**
2405 * Try to calculate hash of the ecma-string
2406 *
2407 * @return calculated hash
2408 */
2409inline lit_string_hash_t JERRY_ATTR_ALWAYS_INLINE
2410ecma_string_hash (const ecma_string_t *string_p) /**< ecma-string to calculate hash for */
2411{
2412  if (ECMA_IS_DIRECT_STRING (string_p))
2413  {
2414    return (lit_string_hash_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
2415  }
2416
2417  return (lit_string_hash_t) string_p->u.hash;
2418} /* ecma_string_hash */
2419
2420/**
2421 * Create a substring from an ecma string
2422 *
2423 * @return a newly consturcted ecma string with its value initialized to a copy of a substring of the first argument
2424 */
2425ecma_string_t *
2426ecma_string_substr (const ecma_string_t *string_p, /**< pointer to an ecma string */
2427                    ecma_length_t start_pos, /**< start position, should be less or equal than string length */
2428                    ecma_length_t end_pos) /**< end position, should be less or equal than string length */
2429{
2430  const ecma_length_t string_length = ecma_string_get_length (string_p);
2431  JERRY_ASSERT (start_pos <= string_length);
2432  JERRY_ASSERT (end_pos <= string_length);
2433
2434  if (start_pos >= end_pos)
2435  {
2436    return ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
2437  }
2438
2439  ecma_string_t *ecma_string_p = NULL;
2440  end_pos -= start_pos;
2441
2442  ECMA_STRING_TO_UTF8_STRING (string_p, start_p, buffer_size);
2443
2444  if (string_length == buffer_size)
2445  {
2446    ecma_string_p = ecma_new_ecma_string_from_utf8 (start_p + start_pos,
2447                                                    (lit_utf8_size_t) end_pos);
2448  }
2449  else
2450  {
2451    while (start_pos--)
2452    {
2453      start_p += lit_get_unicode_char_size_by_utf8_first_byte (*start_p);
2454    }
2455
2456    const lit_utf8_byte_t *end_p = start_p;
2457    while (end_pos--)
2458    {
2459      end_p += lit_get_unicode_char_size_by_utf8_first_byte (*end_p);
2460    }
2461
2462    ecma_string_p = ecma_new_ecma_string_from_utf8 (start_p, (lit_utf8_size_t) (end_p - start_p));
2463  }
2464
2465  ECMA_FINALIZE_UTF8_STRING (start_p, buffer_size);
2466
2467  return ecma_string_p;
2468} /* ecma_string_substr */
2469
2470/**
2471 * Helper function for trimming.
2472 *
2473 * Used by:
2474 *        - ecma_string_trim
2475 *        - ecma_utf8_string_to_number
2476 *        - ecma_builtin_global_object_parse_int
2477 *        - ecma_builtin_global_object_parse_float
2478 */
2479void
2480ecma_string_trim_helper (const lit_utf8_byte_t **utf8_str_p, /**< [in, out] current string position */
2481                         lit_utf8_size_t *utf8_str_size) /**< [in, out] size of the given string */
2482{
2483  ecma_char_t ch;
2484  lit_utf8_size_t read_size;
2485  const lit_utf8_byte_t *nonws_start_p = *utf8_str_p + *utf8_str_size;
2486  const lit_utf8_byte_t *current_p = *utf8_str_p;
2487
2488  while (current_p < nonws_start_p)
2489  {
2490    read_size = lit_read_code_unit_from_utf8 (current_p, &ch);
2491
2492    if (!lit_char_is_white_space (ch))
2493    {
2494      nonws_start_p = current_p;
2495      break;
2496    }
2497
2498    current_p += read_size;
2499  }
2500
2501  current_p = *utf8_str_p + *utf8_str_size;
2502
2503  while (current_p > nonws_start_p)
2504  {
2505    read_size = lit_read_prev_code_unit_from_utf8 (current_p, &ch);
2506
2507    if (!lit_char_is_white_space (ch))
2508    {
2509      break;
2510    }
2511
2512    current_p -= read_size;
2513  }
2514
2515  *utf8_str_p = nonws_start_p;
2516  *utf8_str_size = (lit_utf8_size_t) (current_p - nonws_start_p);
2517} /* ecma_string_trim_helper */
2518
2519/**
2520 * Trim leading and trailing whitespace characters from string.
2521 *
2522 * @return trimmed ecma string
2523 */
2524ecma_string_t *
2525ecma_string_trim (const ecma_string_t *string_p) /**< pointer to an ecma string */
2526{
2527  ecma_string_t *ret_string_p;
2528
2529  lit_utf8_size_t utf8_str_size;
2530  uint8_t flags = ECMA_STRING_FLAG_IS_ASCII;
2531  const lit_utf8_byte_t *utf8_str_p = ecma_string_get_chars (string_p, &utf8_str_size, NULL, NULL, &flags);
2532
2533  if (utf8_str_size > 0)
2534  {
2535    ecma_string_trim_helper (&utf8_str_p, &utf8_str_size);
2536    ret_string_p = ecma_new_ecma_string_from_utf8 (utf8_str_p, utf8_str_size);
2537  }
2538  else
2539  {
2540    ret_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
2541  }
2542
2543  if (flags & ECMA_STRING_FLAG_MUST_BE_FREED)
2544  {
2545    jmem_heap_free_block ((void *) utf8_str_p, utf8_str_size);
2546  }
2547
2548  return ret_string_p;
2549} /* ecma_string_trim */
2550
2551/**
2552 * Create an empty string builder
2553 *
2554 * @return new string builder
2555 */
2556ecma_stringbuilder_t
2557ecma_stringbuilder_create (void)
2558{
2559  const lit_utf8_size_t initial_size = sizeof (ecma_ascii_string_t);
2560  ecma_stringbuilder_header_t *header_p = (ecma_stringbuilder_header_t *) jmem_heap_alloc_block (initial_size);
2561  header_p->current_size = initial_size;
2562#if ENABLED (JERRY_MEM_STATS)
2563  jmem_stats_allocate_string_bytes (initial_size);
2564#endif /* ENABLED (JERRY_MEM_STATS) */
2565
2566  ecma_stringbuilder_t ret = {.header_p = header_p};
2567  return ret;
2568} /* ecma_stringbuilder_create */
2569
2570/**
2571 * Create a string builder from an ecma string
2572 *
2573 * @return new string builder
2574 */
2575ecma_stringbuilder_t
2576ecma_stringbuilder_create_from (ecma_string_t *string_p) /**< ecma string */
2577{
2578  const lit_utf8_size_t string_size = ecma_string_get_size (string_p);
2579  const lit_utf8_size_t initial_size = string_size + (lit_utf8_size_t) sizeof (ecma_ascii_string_t);
2580
2581  ecma_stringbuilder_header_t *header_p = (ecma_stringbuilder_header_t *) jmem_heap_alloc_block (initial_size);
2582  header_p->current_size = initial_size;
2583#if ENABLED (JERRY_MEM_STATS)
2584  jmem_stats_allocate_string_bytes (initial_size);
2585#endif /* ENABLED (JERRY_MEM_STATS) */
2586
2587  size_t copied_size = ecma_string_copy_to_cesu8_buffer (string_p,
2588                                                         ECMA_STRINGBUILDER_STRING_PTR (header_p),
2589                                                         string_size);
2590  JERRY_ASSERT (copied_size == string_size);
2591
2592  ecma_stringbuilder_t ret = {.header_p = header_p};
2593  return ret;
2594} /* ecma_stringbuilder_create_from */
2595
2596/**
2597 * Create a string builder from a raw string
2598 *
2599 * @return new string builder
2600 */
2601ecma_stringbuilder_t
2602ecma_stringbuilder_create_raw (const lit_utf8_byte_t *data_p, /**< pointer to data */
2603                               const lit_utf8_size_t data_size) /**< size of the data */
2604{
2605  const lit_utf8_size_t initial_size = data_size + (lit_utf8_size_t) sizeof (ecma_ascii_string_t);
2606
2607  ecma_stringbuilder_header_t *header_p = (ecma_stringbuilder_header_t *) jmem_heap_alloc_block (initial_size);
2608  header_p->current_size = initial_size;
2609#if ENABLED (JERRY_MEM_STATS)
2610  jmem_stats_allocate_string_bytes (initial_size);
2611#endif /* ENABLED (JERRY_MEM_STATS) */
2612
2613  memcpy (ECMA_STRINGBUILDER_STRING_PTR (header_p), data_p, data_size);
2614
2615  ecma_stringbuilder_t ret = {.header_p = header_p};
2616  return ret;
2617} /* ecma_stringbuilder_create_raw */
2618
2619/**
2620 * Grow the underlying buffer of a string builder
2621 *
2622 * @return pointer to the end of the data in the underlying buffer
2623 */
2624static lit_utf8_byte_t *
2625ecma_stringbuilder_grow (ecma_stringbuilder_t *builder_p, /**< string builder */
2626                         lit_utf8_size_t required_size) /**< required size */
2627{
2628  ecma_stringbuilder_header_t *header_p = builder_p->header_p;
2629  JERRY_ASSERT (header_p != NULL);
2630
2631  const lit_utf8_size_t new_size = header_p->current_size + required_size;
2632  header_p = jmem_heap_realloc_block (header_p, header_p->current_size, new_size);
2633  header_p->current_size = new_size;
2634  builder_p->header_p = header_p;
2635
2636#if ENABLED (JERRY_MEM_STATS)
2637  jmem_stats_allocate_string_bytes (required_size);
2638#endif /* ENABLED (JERRY_MEM_STATS) */
2639
2640  return ((lit_utf8_byte_t *)  header_p) + header_p->current_size - required_size;
2641} /* ecma_stringbuilder_grow */
2642
2643/**
2644 * Get the current size of the string in a string builder
2645 *
2646 * @return the size of the string data
2647 */
2648lit_utf8_size_t
2649ecma_stringbuilder_get_size (ecma_stringbuilder_t *builder_p) /**< string builder */
2650{
2651  ecma_stringbuilder_header_t *header_p = builder_p->header_p;
2652  JERRY_ASSERT (header_p != NULL);
2653
2654  return ECMA_STRINGBUILDER_STRING_SIZE (header_p);
2655} /* ecma_stringbuilder_get_size */
2656
2657/**
2658 * Get pointer to the raw string data in a string builder
2659 *
2660 * @return pointer to the string data
2661 */
2662lit_utf8_byte_t *
2663ecma_stringbuilder_get_data (ecma_stringbuilder_t *builder_p) /**< string builder */
2664{
2665  ecma_stringbuilder_header_t *header_p = builder_p->header_p;
2666  JERRY_ASSERT (header_p != NULL);
2667
2668  return ECMA_STRINGBUILDER_STRING_PTR (header_p);
2669} /* ecma_stringbuilder_get_data */
2670
2671/**
2672 * Revert the string builder to a smaller size
2673 */
2674void
2675ecma_stringbuilder_revert (ecma_stringbuilder_t *builder_p, /**< string builder */
2676                           const lit_utf8_size_t size) /**< new size */
2677{
2678  ecma_stringbuilder_header_t *header_p = builder_p->header_p;
2679  JERRY_ASSERT (header_p != NULL);
2680
2681  const lit_utf8_size_t new_size = size + (lit_utf8_size_t) (sizeof (ecma_ascii_string_t));
2682  JERRY_ASSERT (new_size <= header_p->current_size);
2683
2684#if ENABLED (JERRY_MEM_STATS)
2685  jmem_stats_free_string_bytes (header_p->current_size - new_size);
2686#endif /* ENABLED (JERRY_MEM_STATS) */
2687
2688  header_p = jmem_heap_realloc_block (header_p, header_p->current_size, new_size);
2689  header_p->current_size = new_size;
2690  builder_p->header_p = header_p;
2691} /* ecma_stringbuilder_revert */
2692
2693/**
2694 * Append an ecma_string_t to a string builder
2695 */
2696void
2697ecma_stringbuilder_append (ecma_stringbuilder_t *builder_p, /**< string builder */
2698                           const ecma_string_t *string_p) /**< ecma string */
2699{
2700  const lit_utf8_size_t string_size = ecma_string_get_size (string_p);
2701  lit_utf8_byte_t *dest_p = ecma_stringbuilder_grow (builder_p, string_size);
2702
2703  size_t copied_size = ecma_string_copy_to_cesu8_buffer (string_p,
2704                                                         dest_p,
2705                                                         string_size);
2706  JERRY_ASSERT (copied_size == string_size);
2707} /* ecma_stringbuilder_append */
2708
2709/**
2710 * Append a magic string to a string builder
2711 */
2712void
2713ecma_stringbuilder_append_magic (ecma_stringbuilder_t *builder_p, /**< string builder */
2714                                 const lit_magic_string_id_t id) /**< magic string id */
2715{
2716  const lit_utf8_size_t string_size = lit_get_magic_string_size (id);
2717  lit_utf8_byte_t *dest_p = ecma_stringbuilder_grow (builder_p, string_size);
2718
2719  const lit_utf8_byte_t *string_data_p = lit_get_magic_string_utf8 (id);
2720  memcpy (dest_p, string_data_p, string_size);
2721} /* ecma_stringbuilder_append_magic */
2722
2723/**
2724 * Append raw string data to a string builder
2725 */
2726void
2727ecma_stringbuilder_append_raw (ecma_stringbuilder_t *builder_p, /**< string builder */
2728                               const lit_utf8_byte_t *data_p, /**< pointer to data */
2729                               const lit_utf8_size_t data_size) /**< size of the data */
2730{
2731  lit_utf8_byte_t *dest_p = ecma_stringbuilder_grow (builder_p, data_size);
2732  memcpy (dest_p, data_p, data_size);
2733} /* ecma_stringbuilder_append_raw */
2734
2735/**
2736 * Append an ecma_char_t to a string builder
2737 */
2738void
2739ecma_stringbuilder_append_char (ecma_stringbuilder_t *builder_p, /**< string builder */
2740                                const ecma_char_t c) /**< ecma char */
2741{
2742  const lit_utf8_size_t size = (lit_utf8_size_t) lit_code_point_get_cesu8_length (c);
2743  lit_utf8_byte_t *dest_p = ecma_stringbuilder_grow (builder_p, size);
2744
2745  lit_code_point_to_cesu8_bytes (dest_p, c);
2746} /* ecma_stringbuilder_append_char */
2747
2748/**
2749 * Append a single byte to a string builder
2750 */
2751void
2752ecma_stringbuilder_append_byte (ecma_stringbuilder_t *builder_p, /**< string builder */
2753                                const lit_utf8_byte_t byte) /**< byte */
2754{
2755  lit_utf8_byte_t *dest_p = ecma_stringbuilder_grow (builder_p, 1);
2756  *dest_p = byte;
2757} /* ecma_stringbuilder_append_byte */
2758
2759/**
2760 * Finalize a string builder, returning the created string, and releasing the underlying buffer.
2761 *
2762 * Note:
2763 *      The builder should no longer be used.
2764 *
2765 * @return the created string
2766 */
2767ecma_string_t *
2768ecma_stringbuilder_finalize (ecma_stringbuilder_t *builder_p) /**< string builder */
2769{
2770  ecma_stringbuilder_header_t *header_p = builder_p->header_p;
2771  JERRY_ASSERT (header_p != NULL);
2772
2773  const lit_utf8_size_t string_size = ECMA_STRINGBUILDER_STRING_SIZE (header_p);
2774  lit_utf8_byte_t *string_begin_p = ECMA_STRINGBUILDER_STRING_PTR (header_p);
2775
2776  ecma_string_t *string_p = ecma_find_special_string (string_begin_p, string_size);
2777
2778  if (JERRY_UNLIKELY (string_p != NULL))
2779  {
2780    ecma_stringbuilder_destroy (builder_p);
2781    return string_p;
2782  }
2783
2784#ifndef JERRY_NDEBUG
2785  builder_p->header_p = NULL;
2786#endif
2787
2788  size_t container_size = sizeof (ecma_utf8_string_t);
2789  const lit_string_hash_t hash = lit_utf8_string_calc_hash (string_begin_p, string_size);
2790  const lit_utf8_size_t length = lit_utf8_string_length (string_begin_p, string_size);
2791
2792  if (JERRY_LIKELY (string_size <= UINT16_MAX))
2793  {
2794    if (JERRY_LIKELY (length == string_size))
2795    {
2796      ecma_ascii_string_t *ascii_string_p = (ecma_ascii_string_t *) header_p;
2797      ascii_string_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_ASCII_STRING | ECMA_STRING_REF_ONE;
2798      ascii_string_p->header.u.hash = hash;
2799      ascii_string_p->size = (uint16_t) string_size;
2800
2801      return (ecma_string_t *) ascii_string_p;
2802    }
2803  }
2804  else
2805  {
2806    container_size = sizeof (ecma_long_utf8_string_t);
2807  }
2808
2809  const size_t utf8_string_size = string_size + container_size;
2810  header_p = jmem_heap_realloc_block (header_p, header_p->current_size, utf8_string_size);
2811  memmove (((lit_utf8_byte_t *) header_p + container_size),
2812           ECMA_STRINGBUILDER_STRING_PTR (header_p),
2813           string_size);
2814
2815#if ENABLED (JERRY_MEM_STATS)
2816  jmem_stats_allocate_string_bytes (container_size - sizeof (ecma_ascii_string_t));
2817#endif /* ENABLED (JERRY_MEM_STATS) */
2818
2819  if (JERRY_LIKELY (string_size <= UINT16_MAX))
2820  {
2821    ecma_utf8_string_t *utf8_string_p = (ecma_utf8_string_t *) header_p;
2822
2823    utf8_string_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_UTF8_STRING | ECMA_STRING_REF_ONE;
2824    utf8_string_p->header.u.hash = hash;
2825    utf8_string_p->size = (uint16_t) string_size;
2826    utf8_string_p->length = (uint16_t) length;
2827
2828    return (ecma_string_t *) utf8_string_p;
2829  }
2830
2831  ecma_long_utf8_string_t *long_utf8_string_p = (ecma_long_utf8_string_t *) header_p;
2832
2833  long_utf8_string_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING | ECMA_STRING_REF_ONE;
2834  long_utf8_string_p->header.u.hash = hash;
2835  long_utf8_string_p->size = string_size;
2836  long_utf8_string_p->length = length;
2837
2838  return (ecma_string_t *) long_utf8_string_p;
2839} /* ecma_stringbuilder_finalize */
2840
2841/**
2842 * Destroy a string builder that is no longer needed without creating a string from the contents.
2843 */
2844void
2845ecma_stringbuilder_destroy (ecma_stringbuilder_t *builder_p) /**< string builder */
2846{
2847  JERRY_ASSERT (builder_p->header_p != NULL);
2848  const lit_utf8_size_t size = builder_p->header_p->current_size;
2849  jmem_heap_free_block (builder_p->header_p, size);
2850
2851#ifndef JERRY_NDEBUG
2852  builder_p->header_p = NULL;
2853#endif
2854
2855#if ENABLED (JERRY_MEM_STATS)
2856  jmem_stats_free_string_bytes (size);
2857#endif /* ENABLED (JERRY_MEM_STATS) */
2858} /* ecma_stringbuilder_destroy */
2859
2860#if ENABLED (JERRY_ES2015)
2861/**
2862 * AdvanceStringIndex operation
2863 *
2864 * See also:
2865 *          ECMA-262 v6.0, 21.2.5.2.3
2866 *
2867 * @return uint32_t - the proper character index based on the operation
2868 */
2869uint32_t
2870ecma_op_advance_string_index (ecma_string_t *str_p, /**< input string */
2871                              uint32_t index, /**< given character index */
2872                              bool is_unicode) /**< true - if regexp object's "unicode" flag is set
2873                                                    false - otherwise */
2874{
2875  if (index >= UINT32_MAX - 1)
2876  {
2877    return UINT32_MAX;
2878  }
2879
2880  uint32_t next_index = index + 1;
2881
2882  if (!is_unicode)
2883  {
2884    return next_index;
2885  }
2886
2887  ecma_length_t str_len = ecma_string_get_length (str_p);
2888
2889  if (next_index >= str_len)
2890  {
2891    return next_index;
2892  }
2893
2894  ecma_char_t first = ecma_string_get_char_at_pos (str_p, index);
2895
2896  if (first < LIT_UTF16_HIGH_SURROGATE_MIN || first > LIT_UTF16_HIGH_SURROGATE_MAX)
2897  {
2898    return next_index;
2899  }
2900
2901  ecma_char_t second = ecma_string_get_char_at_pos (str_p, next_index);
2902
2903  if (second < LIT_UTF16_LOW_SURROGATE_MIN || second > LIT_UTF16_LOW_SURROGATE_MAX)
2904  {
2905    return next_index;
2906  }
2907
2908  return next_index + 1;
2909} /* ecma_op_advance_string_index */
2910#endif /* ENABLED (JERRY_ES2015) */
2911
2912/**
2913 * @}
2914 * @}
2915 */
2916