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