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