• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright JS Foundation and other contributors, http://js.foundation
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecma-alloc.h"
17 #include "ecma-array-object.h"
18 #include "ecma-builtin-helpers.h"
19 #include "ecma-builtins.h"
20 #include "ecma-builtin-regexp.inc.h"
21 #include "ecma-conversion.h"
22 #include "ecma-exceptions.h"
23 #include "ecma-function-object.h"
24 #include "ecma-gc.h"
25 #include "ecma-globals.h"
26 #include "ecma-helpers.h"
27 #include "ecma-iterator-object.h"
28 #include "ecma-objects.h"
29 #include "ecma-string-object.h"
30 #include "jcontext.h"
31 #include "jrt.h"
32 #include "jrt-libc-includes.h"
33 #include "lit-char-helpers.h"
34 #include "lit-strings.h"
35 
36 #if ENABLED (JERRY_BUILTIN_REGEXP)
37 #include "ecma-regexp-object.h"
38 #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
39 
40 #if ENABLED (JERRY_BUILTIN_STRING)
41 
42 #define ECMA_BUILTINS_INTERNAL
43 #include "ecma-builtins-internal.h"
44 
45 /**
46  * This object has a custom dispatch function.
47  */
48 #define BUILTIN_CUSTOM_DISPATCH
49 
50 /**
51  * List of built-in routine identifiers.
52  */
53 enum
54 {
55   ECMA_STRING_PROTOTYPE_ROUTINE_START = ECMA_BUILTIN_ID__COUNT - 1,
56   /* Note: These 4 routines MUST be in this order */
57   ECMA_STRING_PROTOTYPE_TO_STRING,
58   ECMA_STRING_PROTOTYPE_VALUE_OF,
59   ECMA_STRING_PROTOTYPE_CHAR_AT,
60   ECMA_STRING_PROTOTYPE_CHAR_CODE_AT,
61 
62   ECMA_STRING_PROTOTYPE_CONCAT,
63   ECMA_STRING_PROTOTYPE_SLICE,
64 
65   ECMA_STRING_PROTOTYPE_LOCALE_COMPARE,
66 
67   ECMA_STRING_PROTOTYPE_MATCH,
68   ECMA_STRING_PROTOTYPE_REPLACE,
69   ECMA_STRING_PROTOTYPE_SEARCH,
70 
71   ECMA_STRING_PROTOTYPE_SPLIT,
72   ECMA_STRING_PROTOTYPE_SUBSTRING,
73   ECMA_STRING_PROTOTYPE_TO_LOWER_CASE,
74   ECMA_STRING_PROTOTYPE_TO_LOCAL_LOWER_CASE,
75   ECMA_STRING_PROTOTYPE_TO_UPPER_CASE,
76   ECMA_STRING_PROTOTYPE_TO_LOCAL_UPPER_CASE,
77   ECMA_STRING_PROTOTYPE_TRIM,
78 
79   ECMA_STRING_PROTOTYPE_SUBSTR,
80 
81   ECMA_STRING_PROTOTYPE_REPEAT,
82   ECMA_STRING_PROTOTYPE_CODE_POINT_AT,
83   /* Note: These 5 routines MUST be in this order */
84   ECMA_STRING_PROTOTYPE_LAST_INDEX_OF,
85   ECMA_STRING_PROTOTYPE_INDEX_OF,
86   ECMA_STRING_PROTOTYPE_STARTS_WITH,
87   ECMA_STRING_PROTOTYPE_INCLUDES,
88   ECMA_STRING_PROTOTYPE_ENDS_WITH,
89 
90   ECMA_STRING_PROTOTYPE_ITERATOR,
91 };
92 
93 #define BUILTIN_INC_HEADER_NAME "ecma-builtin-string-prototype.inc.h"
94 #define BUILTIN_UNDERSCORED_ID string_prototype
95 #include "ecma-builtin-internal-routines-template.inc.h"
96 
97 /** \addtogroup ecma ECMA
98  * @{
99  *
100  * \addtogroup ecmabuiltins
101  * @{
102  *
103  * \addtogroup stringprototype ECMA String.prototype object built-in
104  * @{
105  */
106 
107 /**
108  * The String.prototype object's 'toString' and 'valueOf' routines
109  *
110  * See also:
111  *          ECMA-262 v5, 15.5.4.2
112  *          ECMA-262 v5, 15.5.4.3
113  *
114  * @return ecma value
115  *         Returned value must be freed with ecma_free_value.
116  */
117 static ecma_value_t
ecma_builtin_string_prototype_object_to_string(ecma_value_t this_arg)118 ecma_builtin_string_prototype_object_to_string (ecma_value_t this_arg) /**< this argument */
119 {
120   if (ecma_is_value_string (this_arg))
121   {
122     return ecma_copy_value (this_arg);
123   }
124 
125   if (ecma_is_value_object (this_arg))
126   {
127     ecma_object_t *object_p = ecma_get_object_from_value (this_arg);
128 
129     if (ecma_object_class_is (object_p, LIT_MAGIC_STRING_STRING_UL))
130     {
131       ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
132 
133       JERRY_ASSERT (ecma_is_value_string (ext_object_p->u.class_prop.u.value));
134 
135       return ecma_copy_value (ext_object_p->u.class_prop.u.value);
136     }
137   }
138 
139   return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a String or a String object."));
140 } /* ecma_builtin_string_prototype_object_to_string */
141 
142 /**
143  * Helper function for the String.prototype object's 'charAt' and charCodeAt' routine
144  *
145  * @return ecma value
146  *         Returned value must be freed with ecma_free_value.
147  */
148 static ecma_value_t
ecma_builtin_string_prototype_char_at_helper(ecma_value_t this_arg,ecma_value_t arg,bool charcode_mode)149 ecma_builtin_string_prototype_char_at_helper (ecma_value_t this_arg, /**< this argument */
150                                               ecma_value_t arg, /**< routine's argument */
151                                               bool charcode_mode) /**< routine mode */
152 {
153   /* 3 */
154   ecma_number_t index_num;
155   ecma_value_t to_num_result = ecma_op_to_integer (arg, &index_num);
156 
157   if (JERRY_UNLIKELY (!ecma_is_value_empty (to_num_result)))
158   {
159     return to_num_result;
160   }
161 
162   /* 2 */
163   ecma_string_t *original_string_p = ecma_op_to_string (this_arg);
164   if (JERRY_UNLIKELY (original_string_p == NULL))
165   {
166     return ECMA_VALUE_ERROR;
167   }
168 
169   /* 4 */
170   const ecma_length_t len = ecma_string_get_length (original_string_p);
171 
172   /* 5 */
173   // When index_num is NaN, then the first two comparisons are false
174   if (index_num < 0 || index_num >= len || (ecma_number_is_nan (index_num) && len == 0))
175   {
176     ecma_deref_ecma_string (original_string_p);
177     return (charcode_mode ? ecma_make_nan_value ()
178                           : ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY));
179   }
180 
181   /* 6 */
182   /*
183    * String length is currently uint32_t, but index_num may be bigger,
184    * ToInteger performs floor, while ToUInt32 performs modulo 2^32,
185    * hence after the check 0 <= index_num < len we assume to_uint32 can be used.
186    * We assume to_uint32 (NaN) is 0.
187    */
188   JERRY_ASSERT (ecma_number_is_nan (index_num) || ecma_number_to_uint32 (index_num) == ecma_number_trunc (index_num));
189 
190   ecma_char_t new_ecma_char = ecma_string_get_char_at_pos (original_string_p, ecma_number_to_uint32 (index_num));
191   ecma_deref_ecma_string (original_string_p);
192 
193   return (charcode_mode ? ecma_make_uint32_value (new_ecma_char)
194                         : ecma_make_string_value (ecma_new_ecma_string_from_code_unit (new_ecma_char)));
195 } /* ecma_builtin_string_prototype_char_at_helper */
196 
197 /**
198  * The String.prototype object's 'concat' routine
199  *
200  * See also:
201  *          ECMA-262 v5, 15.5.4.6
202  *
203  * @return ecma value
204  *         Returned value must be freed with ecma_free_value.
205  */
206 static ecma_value_t
ecma_builtin_string_prototype_object_concat(ecma_string_t * this_string_p,const ecma_value_t * argument_list_p,ecma_length_t arguments_number)207 ecma_builtin_string_prototype_object_concat (ecma_string_t *this_string_p, /**< this argument */
208                                              const ecma_value_t *argument_list_p, /**< arguments list */
209                                              ecma_length_t arguments_number) /**< number of arguments */
210 {
211   ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (this_string_p);
212 
213   /* 5 */
214   for (uint32_t arg_index = 0; arg_index < arguments_number; ++arg_index)
215   {
216     /* 5a, b */
217     ecma_string_t *get_arg_string_p = ecma_op_to_string (argument_list_p[arg_index]);
218 
219     if (JERRY_UNLIKELY (get_arg_string_p == NULL))
220     {
221       ecma_stringbuilder_destroy (&builder);
222       return ECMA_VALUE_ERROR;
223     }
224 
225     ecma_stringbuilder_append (&builder, get_arg_string_p);
226 
227     ecma_deref_ecma_string (get_arg_string_p);
228   }
229 
230   /* 6 */
231   return ecma_make_string_value (ecma_stringbuilder_finalize (&builder));
232 } /* ecma_builtin_string_prototype_object_concat */
233 
234 /**
235  * The String.prototype object's 'localeCompare' routine
236  *
237  * See also:
238  *          ECMA-262 v5, 15.5.4.9
239  *
240  * @return ecma value
241  *         Returned value must be freed with ecma_free_value.
242  */
243 static ecma_value_t
ecma_builtin_string_prototype_object_locale_compare(ecma_string_t * this_string_p,ecma_value_t arg)244 ecma_builtin_string_prototype_object_locale_compare (ecma_string_t *this_string_p, /**< this argument */
245                                                      ecma_value_t arg) /**< routine's argument */
246 {
247   /* 3. */
248   ecma_string_t *arg_string_p = ecma_op_to_string (arg);
249 
250   if (JERRY_UNLIKELY (arg_string_p == NULL))
251   {
252     return ECMA_VALUE_ERROR;
253   }
254 
255   ecma_number_t result = ECMA_NUMBER_ZERO;
256 
257   if (ecma_compare_ecma_strings_relational (this_string_p, arg_string_p))
258   {
259     result = ECMA_NUMBER_MINUS_ONE;
260   }
261   else if (!ecma_compare_ecma_strings (this_string_p, arg_string_p))
262   {
263     result = ECMA_NUMBER_ONE;
264   }
265   else
266   {
267     result = ECMA_NUMBER_ZERO;
268   }
269 
270   ecma_deref_ecma_string (arg_string_p);
271 
272   return ecma_make_number_value (result);
273 } /* ecma_builtin_string_prototype_object_locale_compare */
274 
275 #if ENABLED (JERRY_BUILTIN_REGEXP)
276 /**
277  * The String.prototype object's 'match' routine
278  *
279  * See also:
280  *          ECMA-262 v5, 15.5.4.10
281  *
282  * @return ecma value
283  *         Returned value must be freed with ecma_free_value.
284  */
285 static ecma_value_t
ecma_builtin_string_prototype_object_match(ecma_value_t this_argument,ecma_value_t regexp_arg)286 ecma_builtin_string_prototype_object_match (ecma_value_t this_argument, /**< this argument */
287                                             ecma_value_t regexp_arg) /**< routine's argument */
288 {
289 #if ENABLED (JERRY_ES2015)
290   /* 3. */
291   if (!(ecma_is_value_undefined (regexp_arg) || ecma_is_value_null (regexp_arg)))
292   {
293     /* 3.a */
294     ecma_value_t matcher = ecma_op_get_method_by_symbol_id (regexp_arg, LIT_GLOBAL_SYMBOL_MATCH);
295 
296     /* 3.b */
297     if (ECMA_IS_VALUE_ERROR (matcher))
298     {
299       return matcher;
300     }
301 
302     /* 3.c */
303     if (!ecma_is_value_undefined (matcher))
304     {
305       /* 3.c.i */
306       ecma_object_t *matcher_method = ecma_get_object_from_value (matcher);
307       ecma_value_t result = ecma_op_function_call (matcher_method, regexp_arg, &this_argument, 1);
308       ecma_deref_object (matcher_method);
309       return result;
310     }
311   }
312 
313   /* 4. */
314   ecma_string_t *this_str_p = ecma_op_to_string (this_argument);
315 
316   /* 5. */
317   if (JERRY_UNLIKELY (this_str_p == NULL))
318   {
319     return ECMA_VALUE_ERROR;
320   }
321 
322   /* 6. */
323   ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL);
324 
325   if (JERRY_UNLIKELY (regexp_obj_p == NULL))
326   {
327     ecma_deref_ecma_string (this_str_p);
328     return ECMA_VALUE_ERROR;
329   }
330 
331   ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (regexp_obj_p, regexp_arg, ECMA_VALUE_UNDEFINED);
332 
333   /* 7. */
334   if (ECMA_IS_VALUE_ERROR (new_regexp))
335   {
336 
337     ecma_deref_object (regexp_obj_p);
338     ecma_deref_ecma_string (this_str_p);
339     return new_regexp;
340   }
341   ecma_value_t this_str_value = ecma_make_string_value (this_str_p);
342 
343   /* 8. */
344   ecma_value_t ret_value = ecma_op_invoke_by_symbol_id (new_regexp, LIT_GLOBAL_SYMBOL_MATCH, &this_str_value, 1);
345 
346   ecma_deref_ecma_string (this_str_p);
347   ecma_free_value (new_regexp);
348 
349   return ret_value;
350 
351 #else /* !ENABLED (JERRY_ES2015) */
352   if (ecma_object_is_regexp_object (regexp_arg))
353   {
354     return ecma_regexp_match_helper (regexp_arg, this_argument);
355   }
356 
357   ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL);
358 
359   if (JERRY_UNLIKELY (regexp_obj_p == NULL))
360   {
361     return ECMA_VALUE_ERROR;
362   }
363 
364   ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (regexp_obj_p, regexp_arg, ECMA_VALUE_UNDEFINED);
365 
366   if (ECMA_IS_VALUE_ERROR (new_regexp))
367   {
368     ecma_deref_object (regexp_obj_p);
369     return new_regexp;
370   }
371 
372   ecma_value_t result = ecma_regexp_match_helper (new_regexp, this_argument);
373 
374   ecma_free_value (new_regexp);
375 
376   return result;
377 #endif /* ENABLED (JERRY_ES2015) */
378 } /* ecma_builtin_string_prototype_object_match */
379 
380 /**
381  * The String.prototype object's 'replace' routine
382  *
383  * See also:
384  *          ECMA-262 v5, 15.5.4.11
385  *          ECMA-262 v6, 21.1.3.14
386  *
387  * @return ecma value
388  *         Returned value must be freed with ecma_free_value.
389  */
390 static ecma_value_t
ecma_builtin_string_prototype_object_replace(ecma_value_t this_value,ecma_value_t search_value,ecma_value_t replace_value)391 ecma_builtin_string_prototype_object_replace (ecma_value_t this_value, /**< this argument */
392                                               ecma_value_t search_value, /**< routine's first argument */
393                                               ecma_value_t replace_value) /**< routine's second argument */
394 {
395 #if ENABLED (JERRY_ES2015)
396   if (!(ecma_is_value_undefined (search_value) || ecma_is_value_null (search_value)))
397   {
398     ecma_object_t *obj_p = ecma_get_object_from_value (ecma_op_to_object (search_value));
399     ecma_value_t replace_symbol = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_REPLACE);
400     ecma_deref_object (obj_p);
401 
402     if (ECMA_IS_VALUE_ERROR (replace_symbol))
403     {
404       return replace_symbol;
405     }
406 
407     if (!ecma_is_value_undefined (replace_symbol) && !ecma_is_value_null (replace_symbol))
408     {
409       if (!ecma_op_is_callable (replace_symbol))
410       {
411         ecma_free_value (replace_symbol);
412         return ecma_raise_type_error (ECMA_ERR_MSG ("@@replace is not callable"));
413       }
414 
415       ecma_object_t *replace_method = ecma_get_object_from_value (replace_symbol);
416 
417       ecma_value_t arguments[] = { this_value, replace_value };
418       ecma_value_t replace_result = ecma_op_function_call (replace_method, search_value, arguments, 2);
419 
420       ecma_deref_object (replace_method);
421       return replace_result;
422     }
423   }
424 #else /* !ENABLED (JERRY_ES2015) */
425   if (ecma_object_is_regexp_object (search_value))
426   {
427     return ecma_regexp_replace_helper (search_value, this_value, replace_value);
428   }
429 #endif /* ENABLED (JERRY_ES2015) */
430 
431   ecma_string_t *input_str_p = ecma_get_string_from_value (this_value);
432 
433   ecma_value_t result = ECMA_VALUE_ERROR;
434 
435   ecma_string_t *search_str_p = ecma_op_to_string (search_value);
436   if (search_str_p == NULL)
437   {
438     return result;
439   }
440 
441   ecma_replace_context_t replace_ctx;
442   replace_ctx.capture_count = 0;
443   replace_ctx.u.captures_p = NULL;
444 
445   replace_ctx.replace_str_p = NULL;
446   if (!ecma_op_is_callable (replace_value))
447   {
448     replace_ctx.replace_str_p = ecma_op_to_string (replace_value);
449     if (replace_ctx.replace_str_p == NULL)
450     {
451       goto cleanup_search;
452     }
453   }
454 
455   uint8_t input_flags = ECMA_STRING_FLAG_IS_ASCII;
456   replace_ctx.string_p = ecma_string_get_chars (input_str_p,
457                                                 &(replace_ctx.string_size),
458                                                 NULL,
459                                                 NULL,
460                                                 &input_flags);
461 
462   lit_utf8_size_t search_size;
463   uint8_t search_flags = ECMA_STRING_FLAG_IS_ASCII;
464   const lit_utf8_byte_t *search_buf_p = ecma_string_get_chars (search_str_p,
465                                                                &search_size,
466                                                                NULL,
467                                                                NULL,
468                                                                &search_flags);
469 
470   ecma_string_t *result_string_p = NULL;
471 
472   if (replace_ctx.string_size >= search_size)
473   {
474     replace_ctx.matched_size = search_size;
475     const lit_utf8_byte_t *const input_end_p = replace_ctx.string_p + replace_ctx.string_size;
476     const lit_utf8_byte_t *const loop_end_p = input_end_p - search_size;
477 
478     uint32_t pos = 0;
479     for (const lit_utf8_byte_t *curr_p = replace_ctx.string_p;
480          curr_p <= loop_end_p;
481          lit_utf8_incr (&curr_p), pos++)
482     {
483       if (!memcmp (curr_p, search_buf_p, search_size))
484       {
485         const lit_utf8_size_t byte_offset = (lit_utf8_size_t) (curr_p - replace_ctx.string_p);
486         replace_ctx.builder = ecma_stringbuilder_create_raw (replace_ctx.string_p, byte_offset);
487 
488         if (replace_ctx.replace_str_p == NULL)
489         {
490           ecma_object_t *function_p = ecma_get_object_from_value (replace_value);
491 
492           ecma_value_t args[] =
493           {
494             ecma_make_string_value (search_str_p),
495             ecma_make_uint32_value (pos),
496             ecma_make_string_value (input_str_p)
497           };
498 
499           result = ecma_op_function_call (function_p,
500                                           ECMA_VALUE_UNDEFINED,
501                                           args,
502                                           3);
503 
504           if (ECMA_IS_VALUE_ERROR (result))
505           {
506             ecma_stringbuilder_destroy (&replace_ctx.builder);
507             goto cleanup_replace;
508           }
509 
510           ecma_string_t *const result_str_p = ecma_op_to_string (result);
511           ecma_free_value (result);
512 
513           if (result_str_p == NULL)
514           {
515             ecma_stringbuilder_destroy (&replace_ctx.builder);
516             result = ECMA_VALUE_ERROR;
517             goto cleanup_replace;
518           }
519 
520           ecma_stringbuilder_append (&replace_ctx.builder, result_str_p);
521           ecma_deref_ecma_string (result_str_p);
522         }
523         else
524         {
525           replace_ctx.matched_p = curr_p;
526           replace_ctx.match_byte_pos = byte_offset;
527 
528           ecma_builtin_replace_substitute (&replace_ctx);
529         }
530 
531         const lit_utf8_byte_t *const match_end_p = curr_p + search_size;
532         ecma_stringbuilder_append_raw (&replace_ctx.builder,
533                                        match_end_p,
534                                        (lit_utf8_size_t) (input_end_p - match_end_p));
535         result_string_p = ecma_stringbuilder_finalize (&replace_ctx.builder);
536         break;
537       }
538     }
539   }
540 
541   if (result_string_p == NULL)
542   {
543     ecma_ref_ecma_string (input_str_p);
544     result_string_p = input_str_p;
545   }
546 
547   result = ecma_make_string_value (result_string_p);
548 
549 cleanup_replace:
550   if (input_flags & ECMA_STRING_FLAG_MUST_BE_FREED)
551   {
552     jmem_heap_free_block ((void *) replace_ctx.string_p, replace_ctx.string_size);
553   }
554 
555   if (search_flags & ECMA_STRING_FLAG_MUST_BE_FREED)
556   {
557     jmem_heap_free_block ((void *) search_buf_p, search_size);
558   }
559 
560   if (replace_ctx.replace_str_p != NULL)
561   {
562     ecma_deref_ecma_string (replace_ctx.replace_str_p);
563   }
564 
565 cleanup_search:
566   ecma_deref_ecma_string (search_str_p);
567   return result;
568 } /* ecma_builtin_string_prototype_object_replace */
569 
570 /**
571  * The String.prototype object's 'search' routine
572  *
573  * See also:
574  *          ECMA-262 v5, 15.5.4.12
575  *          ECMA-262 v6, 21.1.3.15
576  *
577  * @return ecma value
578  *         Returned value must be freed with ecma_free_value.
579  */
580 static ecma_value_t
ecma_builtin_string_prototype_object_search(ecma_value_t this_value,ecma_value_t regexp_value)581 ecma_builtin_string_prototype_object_search (ecma_value_t this_value, /**< this argument */
582                                              ecma_value_t regexp_value) /**< routine's argument */
583 {
584 #if ENABLED (JERRY_ES2015)
585   if (!(ecma_is_value_undefined (regexp_value) || ecma_is_value_null (regexp_value)))
586   {
587     ecma_object_t *obj_p = ecma_get_object_from_value (ecma_op_to_object (regexp_value));
588     ecma_value_t search_symbol = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_SEARCH);
589     ecma_deref_object (obj_p);
590 
591     if (ECMA_IS_VALUE_ERROR (search_symbol))
592     {
593       return search_symbol;
594     }
595 
596     if (!ecma_is_value_undefined (search_symbol) && !ecma_is_value_null (search_symbol))
597     {
598       if (!ecma_op_is_callable (search_symbol))
599       {
600         ecma_free_value (search_symbol);
601         return ecma_raise_type_error (ECMA_ERR_MSG ("@@search is not callable"));
602       }
603 
604       ecma_object_t *search_method = ecma_get_object_from_value (search_symbol);
605       ecma_value_t search_result = ecma_op_function_call (search_method, regexp_value, &this_value, 1);
606 
607       ecma_deref_object (search_method);
608       return search_result;
609     }
610   }
611 #else /* !ENABLED (JERRY_ES2015) */
612   if (ecma_object_is_regexp_object (regexp_value))
613   {
614     return ecma_regexp_search_helper (regexp_value, this_value);
615   }
616 #endif /* ENABLED (JERRY_ES2015) */
617 
618   ecma_value_t result = ECMA_VALUE_ERROR;
619 
620   ecma_string_t *string_p = ecma_op_to_string (this_value);
621   if (string_p == NULL)
622   {
623     return result;
624   }
625 
626   ecma_string_t *pattern_p = ecma_regexp_read_pattern_str_helper (regexp_value);
627   if (pattern_p == NULL)
628   {
629     goto cleanup_string;
630   }
631 
632   ecma_object_t *new_regexp_obj_p = ecma_op_regexp_alloc (NULL);
633 
634   if (JERRY_UNLIKELY (new_regexp_obj_p == NULL))
635   {
636     ecma_deref_ecma_string (string_p);
637     ecma_deref_ecma_string (pattern_p);
638     return ECMA_VALUE_ERROR;
639   }
640 
641   ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (new_regexp_obj_p,
642                                                                 ecma_make_string_value (pattern_p),
643                                                                 ECMA_VALUE_UNDEFINED);
644 
645   ecma_deref_ecma_string (pattern_p);
646 
647   if (ECMA_IS_VALUE_ERROR (new_regexp))
648   {
649     ecma_deref_object (new_regexp_obj_p);
650     goto cleanup_string;
651   }
652 
653 #if !ENABLED (JERRY_ES2015)
654   result = ecma_regexp_search_helper (new_regexp, ecma_make_string_value (string_p));
655   ecma_deref_object (ecma_get_object_from_value (new_regexp));
656 #else /* ENABLED (JERRY_ES2015) */
657   ecma_object_t *regexp_obj_p = ecma_get_object_from_value (new_regexp);
658   ecma_value_t search_symbol = ecma_op_object_get_by_symbol_id (regexp_obj_p, LIT_GLOBAL_SYMBOL_SEARCH);
659   if (ECMA_IS_VALUE_ERROR (search_symbol))
660   {
661     goto cleanup_regexp;
662   }
663 
664   if (!ecma_op_is_callable (search_symbol))
665   {
666     result = ecma_raise_type_error (ECMA_ERR_MSG ("@@search is not callable"));
667     goto cleanup_regexp;
668   }
669 
670   ecma_object_t *search_method_p = ecma_get_object_from_value (search_symbol);
671   ecma_value_t arguments[] = { ecma_make_string_value (string_p) };
672   result = ecma_op_function_call (search_method_p, new_regexp, arguments, 1);
673   ecma_deref_object (search_method_p);
674 
675 cleanup_regexp:
676   ecma_deref_object (regexp_obj_p);
677 #endif /* !ENABLED (JERRY_ES2015) */
678 
679 cleanup_string:
680   ecma_deref_ecma_string (string_p);
681   return result;
682 } /* ecma_builtin_string_prototype_object_search */
683 
684 #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
685 
686 /**
687  * The String.prototype object's 'slice' routine
688  *
689  * See also:
690  *          ECMA-262 v5, 15.5.4.13
691  *
692  * @return ecma value
693  *         Returned value must be freed with ecma_free_value.
694  */
695 static ecma_value_t
ecma_builtin_string_prototype_object_slice(ecma_string_t * get_string_val,ecma_value_t arg1,ecma_value_t arg2)696 ecma_builtin_string_prototype_object_slice (ecma_string_t *get_string_val, /**< this argument */
697                                             ecma_value_t arg1, /**< routine's first argument */
698                                             ecma_value_t arg2) /**< routine's second argument */
699 {
700   const ecma_length_t len = ecma_string_get_length (get_string_val);
701 
702   /* 4. 6. */
703   ecma_length_t start = 0, end = len;
704 
705   if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (arg1,
706                                                                       len,
707                                                                       &start)))
708   {
709     return ECMA_VALUE_ERROR;
710   }
711 
712   /* 5. 7. */
713   if (ecma_is_value_undefined (arg2))
714   {
715     end = len;
716   }
717   else
718   {
719     if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (arg2,
720                                                                         len,
721                                                                         &end)))
722     {
723       return ECMA_VALUE_ERROR;
724     }
725   }
726 
727   JERRY_ASSERT (start <= len && end <= len);
728 
729   /* 8-9. */
730   ecma_string_t *new_str_p = ecma_string_substr (get_string_val, start, end);
731 
732   return ecma_make_string_value (new_str_p);
733 } /* ecma_builtin_string_prototype_object_slice */
734 
735 /**
736  * The String.prototype object's 'split' routine
737  *
738  * See also:
739  *          ECMA-262 v5, 15.5.4.14
740  *
741  * @return ecma value
742  *         Returned value must be freed with ecma_free_value.
743  */
744 static ecma_value_t
ecma_builtin_string_prototype_object_split(ecma_value_t this_value,ecma_value_t separator_value,ecma_value_t limit_value)745 ecma_builtin_string_prototype_object_split (ecma_value_t this_value, /**< this argument */
746                                             ecma_value_t separator_value, /**< separator */
747                                             ecma_value_t limit_value) /**< limit */
748 {
749 #if ENABLED (JERRY_ES2015)
750   if (!(ecma_is_value_undefined (separator_value) || ecma_is_value_null (separator_value)))
751   {
752     ecma_object_t *obj_p = ecma_get_object_from_value (ecma_op_to_object (separator_value));
753     ecma_value_t split_symbol = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_SPLIT);
754     ecma_deref_object (obj_p);
755 
756     if (ECMA_IS_VALUE_ERROR (split_symbol))
757     {
758       return split_symbol;
759     }
760 
761     if (!ecma_is_value_undefined (split_symbol) && !ecma_is_value_null (split_symbol))
762     {
763       if (!ecma_op_is_callable (split_symbol))
764       {
765         ecma_free_value (split_symbol);
766         return ecma_raise_type_error (ECMA_ERR_MSG ("@@split is not callable"));
767       }
768 
769       ecma_object_t *split_method_p = ecma_get_object_from_value (split_symbol);
770 
771       ecma_value_t arguments[] = { this_value, limit_value };
772       ecma_value_t split_result = ecma_op_function_call (split_method_p, separator_value, arguments, 2);
773 
774       ecma_deref_object (split_method_p);
775       return split_result;
776     }
777   }
778 #else /* !ENABLED (JERRY_ES2015) */
779   if (ecma_object_is_regexp_object (separator_value))
780   {
781 #if ENABLED (JERRY_BUILTIN_REGEXP)
782     return ecma_regexp_split_helper (separator_value, this_value, limit_value);
783 #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
784   }
785 #endif /* ENABLED (JERRY_ES2015) */
786 
787   ecma_value_t result = ECMA_VALUE_ERROR;
788 
789   /* 4. */
790   ecma_string_t *string_p = ecma_op_to_string (this_value);
791   if (string_p == NULL)
792   {
793     return result;
794   }
795 
796   /* 8. */
797   uint32_t limit = UINT32_MAX;
798   if (!ecma_is_value_undefined (limit_value))
799   {
800     if (ECMA_IS_VALUE_ERROR (ecma_op_to_length (limit_value, &limit)))
801     {
802       goto cleanup_string;
803     }
804   }
805 
806   /* 12. */
807   ecma_string_t *separator_p = ecma_op_to_string (separator_value);
808   if (separator_p == NULL)
809   {
810     goto cleanup_string;
811   }
812 
813   /* 6. */
814   result = ecma_op_create_array_object (NULL, 0, false);
815 
816   /* 14. */
817   if (limit == 0)
818   {
819     goto cleanup_separator;
820   }
821 
822   ecma_object_t *array_p = ecma_get_object_from_value (result);
823   ecma_length_t array_length = 0;
824 
825   /* 15. */
826   if (ecma_is_value_undefined (separator_value))
827   {
828     ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p,
829                                                                      array_length,
830                                                                      ecma_make_string_value (string_p),
831                                                                      ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
832     JERRY_ASSERT (put_result == ECMA_VALUE_TRUE);
833     goto cleanup_separator;
834   }
835 
836   /* 16. */
837   if (ecma_string_is_empty (string_p))
838   {
839     if (!ecma_string_is_empty (separator_p))
840     {
841       ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p,
842                                                                        array_length,
843                                                                        ecma_make_string_value (string_p),
844                                                                        ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
845       JERRY_ASSERT (put_result == ECMA_VALUE_TRUE);
846     }
847 
848     goto cleanup_separator;
849   }
850 
851   lit_utf8_size_t string_size;
852   uint8_t string_flags = ECMA_STRING_FLAG_IS_ASCII;
853   const lit_utf8_byte_t *string_buffer_p = ecma_string_get_chars (string_p,
854                                                                   &string_size,
855                                                                   NULL,
856                                                                   NULL,
857                                                                   &string_flags);
858   lit_utf8_size_t separator_size;
859   uint8_t separator_flags = ECMA_STRING_FLAG_IS_ASCII;
860   const lit_utf8_byte_t *separator_buffer_p = ecma_string_get_chars (separator_p,
861                                                                      &separator_size,
862                                                                      NULL,
863                                                                      NULL,
864                                                                      &separator_flags);
865 
866   const lit_utf8_byte_t *const string_end_p = string_buffer_p + string_size;
867   const lit_utf8_byte_t *const compare_end_p = JERRY_MIN (string_end_p - separator_size + 1,
868                                                           string_end_p);
869   const lit_utf8_byte_t *current_p = string_buffer_p;
870   const lit_utf8_byte_t *last_str_begin_p = string_buffer_p;
871 
872   while (current_p < compare_end_p)
873   {
874     if (!memcmp (current_p, separator_buffer_p, separator_size)
875         && (last_str_begin_p != current_p + separator_size))
876     {
877       ecma_string_t *substr_p = ecma_new_ecma_string_from_utf8 (last_str_begin_p,
878                                                                 (lit_utf8_size_t) (current_p - last_str_begin_p));
879       ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p,
880                                                                        array_length++,
881                                                                        ecma_make_string_value (substr_p),
882                                                                        ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
883       JERRY_ASSERT (put_result == ECMA_VALUE_TRUE);
884       ecma_deref_ecma_string (substr_p);
885 
886       if (array_length >= limit)
887       {
888         goto cleanup_buffers;
889       }
890 
891       current_p += separator_size;
892       last_str_begin_p = current_p;
893       continue;
894     }
895 
896     lit_utf8_incr (&current_p);
897   }
898 
899   ecma_string_t *end_substr_p = ecma_new_ecma_string_from_utf8 (last_str_begin_p,
900                                                                 (lit_utf8_size_t) (string_end_p - last_str_begin_p));
901   ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p,
902                                                                    array_length,
903                                                                    ecma_make_string_value (end_substr_p),
904                                                                    ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
905   JERRY_ASSERT (put_result == ECMA_VALUE_TRUE);
906   ecma_deref_ecma_string (end_substr_p);
907 
908 cleanup_buffers:
909   if (string_flags & ECMA_STRING_FLAG_MUST_BE_FREED)
910   {
911     jmem_heap_free_block ((void *) string_buffer_p, string_size);
912   }
913 
914   if (separator_flags & ECMA_STRING_FLAG_MUST_BE_FREED)
915   {
916     jmem_heap_free_block ((void *) separator_buffer_p, separator_size);
917   }
918 
919 cleanup_separator:
920   ecma_deref_ecma_string (separator_p);
921 cleanup_string:
922   ecma_deref_ecma_string (string_p);
923   return result;
924 } /* ecma_builtin_string_prototype_object_split */
925 
926 /**
927  * The String.prototype object's 'substring' routine
928  *
929  * See also:
930  *          ECMA-262 v5, 15.5.4.15
931  *
932  * @return ecma value
933  *         Returned value must be freed with ecma_free_value.
934  */
935 static ecma_value_t
ecma_builtin_string_prototype_object_substring(ecma_string_t * original_string_p,ecma_value_t arg1,ecma_value_t arg2)936 ecma_builtin_string_prototype_object_substring (ecma_string_t *original_string_p, /**< this argument */
937                                                 ecma_value_t arg1, /**< routine's first argument */
938                                                 ecma_value_t arg2) /**< routine's second argument */
939 {
940   /* 3 */
941   const ecma_length_t len = ecma_string_get_length (original_string_p);
942   ecma_length_t start = 0, end = len;
943 
944   /* 4 */
945   ecma_number_t start_num;
946 
947   if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arg1, &start_num)))
948   {
949     return ECMA_VALUE_ERROR;
950   }
951 
952   /* 6 */
953   start = (uint32_t) JERRY_MIN (JERRY_MAX (start_num, 0), len);
954 
955   /* 5 */
956   if (ecma_is_value_undefined (arg2))
957   {
958     end = len;
959   }
960   else
961   {
962     /* 5 part 2 */
963     ecma_number_t end_num;
964 
965     if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arg2, &end_num)))
966     {
967       return ECMA_VALUE_ERROR;
968     }
969     /* 7 */
970     end = (uint32_t) JERRY_MIN (JERRY_MAX (end_num, 0), len);
971   }
972 
973   JERRY_ASSERT (start <= len && end <= len);
974 
975   /* 8 */
976   uint32_t from = start < end ? start : end;
977 
978   /* 9 */
979   uint32_t to = start > end ? start : end;
980 
981   /* 10 */
982   ecma_string_t *new_str_p = ecma_string_substr (original_string_p, from, to);
983   return ecma_make_string_value (new_str_p);
984 } /* ecma_builtin_string_prototype_object_substring */
985 
986 /**
987  * The common implementation of the String.prototype object's
988  * 'toLowerCase', 'toLocaleLowerCase', 'toUpperCase', 'toLocalUpperCase' routines
989  *
990  * See also:
991  *          ECMA-262 v5, 15.5.4.16
992  *          ECMA-262 v5, 15.5.4.17
993  *          ECMA-262 v5, 15.5.4.18
994  *          ECMA-262 v5, 15.5.4.19
995  *
996  * Helper function to convert a string to upper or lower case.
997  *
998  * @return ecma value
999  *         Returned value must be freed with ecma_free_value.
1000  */
1001 static ecma_value_t
ecma_builtin_string_prototype_object_conversion_helper(ecma_string_t * input_string_p,bool lower_case)1002 ecma_builtin_string_prototype_object_conversion_helper (ecma_string_t *input_string_p, /**< this argument */
1003                                                         bool lower_case) /**< convert to lower (true)
1004                                                                           *   or upper (false) case */
1005 {
1006   ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1007 
1008   /* 3. */
1009   ECMA_STRING_TO_UTF8_STRING (input_string_p, input_start_p, input_start_size);
1010 
1011   /*
1012    * The URI encoding has two major phases: first we compute
1013    * the length of the lower case string, then we encode it.
1014    */
1015 
1016   lit_utf8_size_t output_length = 0;
1017   const lit_utf8_byte_t *input_str_curr_p = input_start_p;
1018   const lit_utf8_byte_t *input_str_end_p = input_start_p + input_start_size;
1019 
1020   while (input_str_curr_p < input_str_end_p)
1021   {
1022     ecma_char_t character = lit_cesu8_read_next (&input_str_curr_p);
1023     ecma_char_t character_buffer[LIT_MAXIMUM_OTHER_CASE_LENGTH];
1024     ecma_length_t character_length;
1025     lit_utf8_byte_t utf8_byte_buffer[LIT_CESU8_MAX_BYTES_IN_CODE_POINT];
1026 
1027     if (lower_case)
1028     {
1029       character_length = lit_char_to_lower_case (character,
1030                                                  character_buffer,
1031                                                  LIT_MAXIMUM_OTHER_CASE_LENGTH);
1032     }
1033     else
1034     {
1035       character_length = lit_char_to_upper_case (character,
1036                                                  character_buffer,
1037                                                  LIT_MAXIMUM_OTHER_CASE_LENGTH);
1038     }
1039 
1040     JERRY_ASSERT (character_length >= 1 && character_length <= LIT_MAXIMUM_OTHER_CASE_LENGTH);
1041 
1042     for (ecma_length_t i = 0; i < character_length; i++)
1043     {
1044       output_length += lit_code_unit_to_utf8 (character_buffer[i], utf8_byte_buffer);
1045     }
1046   }
1047 
1048   /* Second phase. */
1049 
1050   JMEM_DEFINE_LOCAL_ARRAY (output_start_p,
1051                            output_length,
1052                            lit_utf8_byte_t);
1053 
1054   lit_utf8_byte_t *output_char_p = output_start_p;
1055 
1056   /* Encoding the output. */
1057   input_str_curr_p = input_start_p;
1058 
1059   while (input_str_curr_p < input_str_end_p)
1060   {
1061     ecma_char_t character = lit_cesu8_read_next (&input_str_curr_p);
1062     ecma_char_t character_buffer[LIT_MAXIMUM_OTHER_CASE_LENGTH];
1063     ecma_length_t character_length;
1064 
1065     if (lower_case)
1066     {
1067       character_length = lit_char_to_lower_case (character,
1068                                                  character_buffer,
1069                                                  LIT_MAXIMUM_OTHER_CASE_LENGTH);
1070     }
1071     else
1072     {
1073       character_length = lit_char_to_upper_case (character,
1074                                                  character_buffer,
1075                                                  LIT_MAXIMUM_OTHER_CASE_LENGTH);
1076     }
1077 
1078     JERRY_ASSERT (character_length >= 1 && character_length <= LIT_MAXIMUM_OTHER_CASE_LENGTH);
1079 
1080     for (ecma_length_t i = 0; i < character_length; i++)
1081     {
1082       output_char_p += lit_code_unit_to_utf8 (character_buffer[i], output_char_p);
1083     }
1084   }
1085 
1086   JERRY_ASSERT (output_start_p + output_length == output_char_p);
1087 
1088   ecma_string_t *output_string_p = ecma_new_ecma_string_from_utf8 (output_start_p, output_length);
1089 
1090   ret_value = ecma_make_string_value (output_string_p);
1091 
1092   JMEM_FINALIZE_LOCAL_ARRAY (output_start_p);
1093   ECMA_FINALIZE_UTF8_STRING (input_start_p, input_start_size);
1094 
1095   return ret_value;
1096 } /* ecma_builtin_string_prototype_object_conversion_helper */
1097 
1098 /**
1099  * The String.prototype object's 'trim' routine
1100  *
1101  * See also:
1102  *          ECMA-262 v5, 15.5.4.20
1103  *
1104  * @return ecma value
1105  *         Returned value must be freed with ecma_free_value.
1106  */
1107 static ecma_value_t
ecma_builtin_string_prototype_object_trim(ecma_string_t * original_string_p)1108 ecma_builtin_string_prototype_object_trim (ecma_string_t *original_string_p) /**< this argument */
1109 {
1110   ecma_string_t *trimmed_string_p = ecma_string_trim (original_string_p);
1111 
1112   return ecma_make_string_value (trimmed_string_p);
1113 } /* ecma_builtin_string_prototype_object_trim */
1114 
1115 #if ENABLED (JERRY_ES2015)
1116 
1117 /**
1118  * The String.prototype object's 'repeat' routine
1119  *
1120  * See also:
1121  *          ECMA-262 v6, 21.1.3.13
1122  *
1123  * @return ecma value
1124  *         Returned value must be freed with ecma_free_value.
1125  */
1126 static ecma_value_t
ecma_builtin_string_prototype_object_repeat(ecma_string_t * original_string_p,ecma_value_t repeat)1127 ecma_builtin_string_prototype_object_repeat (ecma_string_t *original_string_p, /**< this argument */
1128                                              ecma_value_t repeat) /**< times to repeat */
1129 {
1130   ecma_string_t *ret_string_p;
1131 
1132   /* 4 */
1133   ecma_number_t count_number;
1134   ecma_value_t count_value = ecma_op_to_integer (repeat, &count_number);
1135 
1136   /* 5 */
1137   if (ECMA_IS_VALUE_ERROR (count_value))
1138   {
1139     return count_value;
1140   }
1141 
1142   int32_t repeat_count = ecma_number_to_int32 (count_number);
1143 
1144   bool isNan = ecma_number_is_nan (count_number);
1145 
1146   /* 6, 7 */
1147   if (count_number < 0 || (!isNan && ecma_number_is_infinity (count_number)))
1148   {
1149     return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid count value"));
1150   }
1151 
1152   lit_utf8_size_t size = ecma_string_get_size (original_string_p);
1153 
1154   if (repeat_count == 0 || size == 0 || isNan)
1155   {
1156     return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
1157   }
1158 
1159   if ((uint32_t) repeat_count >= (ECMA_STRING_SIZE_LIMIT / size))
1160   {
1161     return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid string length"));
1162   }
1163 
1164   lit_utf8_size_t total_size = size * (lit_utf8_size_t) repeat_count;
1165 
1166   JMEM_DEFINE_LOCAL_ARRAY (str_buffer, total_size, lit_utf8_byte_t);
1167 
1168   lit_utf8_byte_t *buffer_ptr = str_buffer;
1169 
1170   for (int32_t n = 0; n < repeat_count; n++)
1171   {
1172     buffer_ptr += ecma_string_copy_to_cesu8_buffer (original_string_p, buffer_ptr,
1173                                                     (lit_utf8_size_t) (size));
1174   }
1175 
1176   ret_string_p = ecma_new_ecma_string_from_utf8 (str_buffer, (lit_utf8_size_t) (buffer_ptr - str_buffer));
1177   JMEM_FINALIZE_LOCAL_ARRAY (str_buffer);
1178 
1179   return ecma_make_string_value (ret_string_p);
1180 } /* ecma_builtin_string_prototype_object_repeat */
1181 
1182 /**
1183  * The String.prototype object's 'codePointAt' routine
1184  *
1185  * See also:
1186  *          ECMA-262 v6, 21.1.3.3
1187  *
1188  * @return lit_code_point_t
1189  */
1190 static ecma_value_t
ecma_builtin_string_prototype_object_code_point_at(ecma_string_t * this_string_p,ecma_value_t pos)1191 ecma_builtin_string_prototype_object_code_point_at (ecma_string_t *this_string_p, /**< this argument */
1192                                                     ecma_value_t pos) /**< given position */
1193 {
1194   ecma_number_t pos_num;
1195   ecma_value_t error = ecma_op_to_integer (pos, &pos_num);
1196 
1197   if (ECMA_IS_VALUE_ERROR (error))
1198   {
1199     return error;
1200   }
1201 
1202   ecma_length_t size = ecma_string_get_length (this_string_p);
1203 
1204   if (pos_num < 0 || pos_num >= size)
1205   {
1206     return ECMA_VALUE_UNDEFINED;
1207   }
1208 
1209   uint32_t index = (uint32_t) pos_num;
1210 
1211   ecma_char_t first = ecma_string_get_char_at_pos (this_string_p, index);
1212 
1213   if (first < LIT_UTF16_HIGH_SURROGATE_MIN
1214       || first > LIT_UTF16_HIGH_SURROGATE_MAX
1215       || index + 1 == size)
1216   {
1217     return ecma_make_uint32_value (first);
1218   }
1219 
1220   ecma_char_t second = ecma_string_get_char_at_pos (this_string_p, index + 1);
1221 
1222   if (second < LIT_UTF16_LOW_SURROGATE_MARKER
1223       || second > LIT_UTF16_LOW_SURROGATE_MAX)
1224   {
1225     return ecma_make_uint32_value (first);
1226   }
1227 
1228   return ecma_make_uint32_value (lit_convert_surrogate_pair_to_code_point (first, second));
1229 } /* ecma_builtin_string_prototype_object_code_point_at */
1230 
1231 #endif /* ENABLED (JERRY_ES2015) */
1232 
1233 #if ENABLED (JERRY_BUILTIN_ANNEXB)
1234 
1235 /**
1236  * The String.prototype object's 'substr' routine
1237  *
1238  * See also:
1239  *          ECMA-262 v5, B.2.3
1240  *
1241  * @return ecma value
1242  *         Returned value must be freed with ecma_free_value.
1243  */
1244 static ecma_value_t
ecma_builtin_string_prototype_object_substr(ecma_string_t * this_string_p,ecma_value_t start,ecma_value_t length)1245 ecma_builtin_string_prototype_object_substr (ecma_string_t *this_string_p, /**< this argument */
1246                                              ecma_value_t start, /**< routine's first argument */
1247                                              ecma_value_t length) /**< routine's second argument */
1248 {
1249   /* 2. */
1250   ecma_number_t start_num;
1251 
1252   if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (start, &start_num)))
1253   {
1254     return ECMA_VALUE_ERROR;
1255   }
1256 
1257   /* 3. */
1258   ecma_number_t length_num = ecma_number_make_infinity (false);
1259 
1260   if (!ecma_is_value_undefined (length))
1261   {
1262     ecma_number_t len;
1263 
1264     if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (length, &len)))
1265     {
1266       return ECMA_VALUE_ERROR;
1267     }
1268 
1269     length_num = ecma_number_is_nan (len) ? 0 : len;
1270   }
1271 
1272   /* 4. */
1273   ecma_length_t this_len = ecma_string_get_length (this_string_p);
1274 
1275   /* 5. */
1276   uint32_t from = (uint32_t) ((start_num < 0) ? JERRY_MAX (this_len + start_num, 0) : start_num);
1277 
1278   if (from > this_len)
1279   {
1280     from = this_len;
1281   }
1282 
1283   /* 6. */
1284   ecma_number_t to_num = JERRY_MIN (JERRY_MAX (length_num, 0), this_len - from);
1285 
1286   /* 7. */
1287   uint32_t to = from + (uint32_t) to_num;
1288 
1289   /* 8. */
1290   ecma_string_t *new_str_p = ecma_string_substr (this_string_p, from, to);
1291   return ecma_make_string_value (new_str_p);
1292 } /* ecma_builtin_string_prototype_object_substr */
1293 
1294 #endif /* ENABLED (JERRY_BUILTIN_ANNEXB) */
1295 
1296 #if ENABLED (JERRY_ES2015)
1297 
1298 /**
1299  * The String.prototype object's @@iterator routine
1300  *
1301  * See also:
1302  *          ECMA-262 v6, 21.1.3.27
1303  *
1304  * @return ecma value
1305  *         Returned value must be freed with ecma_free_value.
1306  */
1307 static ecma_value_t
ecma_builtin_string_prototype_object_iterator(ecma_value_t to_string)1308 ecma_builtin_string_prototype_object_iterator (ecma_value_t to_string) /**< this argument */
1309 {
1310   return ecma_op_create_iterator_object (ecma_copy_value (to_string),
1311                                          ecma_builtin_get (ECMA_BUILTIN_ID_STRING_ITERATOR_PROTOTYPE),
1312                                          ECMA_PSEUDO_STRING_ITERATOR,
1313                                          0);
1314 } /* ecma_builtin_string_prototype_object_iterator */
1315 
1316 #endif /* ENABLED (JERRY_ES2015) */
1317 
1318 /**
1319  * Dispatcher of the built-in's routines
1320  *
1321  * @return ecma value
1322  *         Returned value must be freed with ecma_free_value.
1323  */
1324 ecma_value_t
ecma_builtin_string_prototype_dispatch_routine(uint16_t builtin_routine_id,ecma_value_t this_arg,const ecma_value_t arguments_list_p[],ecma_length_t arguments_number)1325 ecma_builtin_string_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< built-in wide routine
1326                                                                               *   identifier */
1327                                                 ecma_value_t this_arg, /**< 'this' argument value */
1328                                                 const ecma_value_t arguments_list_p[], /**< list of arguments
1329                                                                                       *   passed to routine */
1330                                                 ecma_length_t arguments_number) /**< length of arguments' list */
1331 {
1332   if (builtin_routine_id <= ECMA_STRING_PROTOTYPE_VALUE_OF)
1333   {
1334     return ecma_builtin_string_prototype_object_to_string (this_arg);
1335   }
1336 
1337   ecma_value_t coercible = ecma_op_check_object_coercible (this_arg);
1338 
1339   if (ECMA_IS_VALUE_ERROR (coercible))
1340   {
1341     return coercible;
1342   }
1343 
1344   ecma_value_t arg1 = arguments_list_p[0];
1345   ecma_value_t arg2 = arguments_list_p[1];
1346 
1347 #if ENABLED (JERRY_BUILTIN_REGEXP)
1348   if (builtin_routine_id == ECMA_STRING_PROTOTYPE_MATCH)
1349   {
1350     return ecma_builtin_string_prototype_object_match (this_arg, arg1);
1351   }
1352 #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
1353 
1354   if (builtin_routine_id <= ECMA_STRING_PROTOTYPE_CHAR_CODE_AT)
1355   {
1356     return ecma_builtin_string_prototype_char_at_helper (this_arg,
1357                                                          arg1,
1358                                                          builtin_routine_id == ECMA_STRING_PROTOTYPE_CHAR_CODE_AT);
1359   }
1360 
1361   ecma_string_t *string_p = ecma_op_to_string (this_arg);
1362 
1363   if (JERRY_UNLIKELY (string_p == NULL))
1364   {
1365     return ECMA_VALUE_ERROR;
1366   }
1367 
1368   ecma_value_t to_string_val = ecma_make_string_value (string_p);
1369   ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1370 
1371   switch (builtin_routine_id)
1372   {
1373     case ECMA_STRING_PROTOTYPE_CONCAT:
1374     {
1375       ret_value = ecma_builtin_string_prototype_object_concat (string_p, arguments_list_p, arguments_number);
1376       break;
1377     }
1378     case ECMA_STRING_PROTOTYPE_SLICE:
1379     {
1380       ret_value = ecma_builtin_string_prototype_object_slice (string_p, arg1, arg2);
1381       break;
1382     }
1383     case ECMA_STRING_PROTOTYPE_LAST_INDEX_OF:
1384     case ECMA_STRING_PROTOTYPE_INDEX_OF:
1385 #if ENABLED (JERRY_ES2015)
1386     case ECMA_STRING_PROTOTYPE_STARTS_WITH:
1387     case ECMA_STRING_PROTOTYPE_INCLUDES:
1388     case ECMA_STRING_PROTOTYPE_ENDS_WITH:
1389 #endif /* ENABLED (JERRY_ES2015) */
1390     {
1391       ecma_string_index_of_mode_t mode;
1392       mode = (ecma_string_index_of_mode_t) (builtin_routine_id - ECMA_STRING_PROTOTYPE_LAST_INDEX_OF);
1393       ret_value = ecma_builtin_helper_string_prototype_object_index_of (string_p, arg1, arg2, mode);
1394       break;
1395     }
1396     case ECMA_STRING_PROTOTYPE_LOCALE_COMPARE:
1397     {
1398       ret_value = ecma_builtin_string_prototype_object_locale_compare (string_p, arg1);
1399       break;
1400     }
1401 #if ENABLED (JERRY_BUILTIN_REGEXP)
1402     case ECMA_STRING_PROTOTYPE_REPLACE:
1403     {
1404       ret_value = ecma_builtin_string_prototype_object_replace (to_string_val, arg1, arg2);
1405       break;
1406     }
1407     case ECMA_STRING_PROTOTYPE_SEARCH:
1408     {
1409       ret_value = ecma_builtin_string_prototype_object_search (to_string_val, arg1);
1410       break;
1411     }
1412 #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
1413     case ECMA_STRING_PROTOTYPE_SPLIT:
1414     {
1415       ret_value = ecma_builtin_string_prototype_object_split (to_string_val, arg1, arg2);
1416       break;
1417     }
1418     case ECMA_STRING_PROTOTYPE_SUBSTRING:
1419     {
1420       ret_value = ecma_builtin_string_prototype_object_substring (string_p, arg1, arg2);
1421       break;
1422     }
1423     case ECMA_STRING_PROTOTYPE_TO_LOWER_CASE:
1424     case ECMA_STRING_PROTOTYPE_TO_LOCAL_LOWER_CASE:
1425     case ECMA_STRING_PROTOTYPE_TO_UPPER_CASE:
1426     case ECMA_STRING_PROTOTYPE_TO_LOCAL_UPPER_CASE:
1427     {
1428       bool is_lower_case = builtin_routine_id <= ECMA_STRING_PROTOTYPE_TO_LOCAL_LOWER_CASE;
1429       ret_value = ecma_builtin_string_prototype_object_conversion_helper (string_p, is_lower_case);
1430       break;
1431     }
1432     case ECMA_STRING_PROTOTYPE_TRIM:
1433     {
1434       ret_value = ecma_builtin_string_prototype_object_trim (string_p);
1435       break;
1436     }
1437 #if ENABLED (JERRY_BUILTIN_ANNEXB)
1438     case ECMA_STRING_PROTOTYPE_SUBSTR:
1439     {
1440       ret_value = ecma_builtin_string_prototype_object_substr (string_p, arg1, arg2);
1441       break;
1442     }
1443 #endif /* ENABLED (JERRY_BUILTIN_ANNEXB) */
1444 #if ENABLED (JERRY_ES2015)
1445     case ECMA_STRING_PROTOTYPE_REPEAT:
1446     {
1447       ret_value = ecma_builtin_string_prototype_object_repeat (string_p, arg1);
1448       break;
1449     }
1450     case ECMA_STRING_PROTOTYPE_CODE_POINT_AT:
1451     {
1452       ret_value = ecma_builtin_string_prototype_object_code_point_at (string_p, arg1);
1453       break;
1454     }
1455     case ECMA_STRING_PROTOTYPE_ITERATOR:
1456     {
1457       ret_value = ecma_builtin_string_prototype_object_iterator (to_string_val);
1458       break;
1459     }
1460 #endif /* ENABLED (JERRY_ES2015) */
1461     default:
1462     {
1463       JERRY_UNREACHABLE ();
1464     }
1465   }
1466 
1467   ecma_deref_ecma_string (string_p);
1468 
1469   return ret_value;
1470 } /* ecma_builtin_string_prototype_dispatch_routine */
1471 
1472 /**
1473  * @}
1474  * @}
1475  * @}
1476  */
1477 
1478 #endif /* ENABLED (JERRY_BUILTIN_STRING) */
1479