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-builtins.h" 18#include "ecma-builtin-helpers.h" 19#include "ecma-conversion.h" 20#include "ecma-exceptions.h" 21#include "ecma-function-object.h" 22#include "ecma-gc.h" 23#include "ecma-globals.h" 24#include "ecma-helpers.h" 25#include "ecma-iterator-object.h" 26#include "ecma-objects.h" 27#include "ecma-array-object.h" 28#include "jcontext.h" 29#include "jrt.h" 30 31#if ENABLED (JERRY_BUILTIN_ARRAY) 32 33#define ECMA_BUILTINS_INTERNAL 34#include "ecma-builtins-internal.h" 35 36#define BUILTIN_INC_HEADER_NAME "ecma-builtin-array.inc.h" 37#define BUILTIN_UNDERSCORED_ID array 38#include "ecma-builtin-internal-routines-template.inc.h" 39 40/** \addtogroup ecma ECMA 41 * @{ 42 * 43 * \addtogroup ecmabuiltins 44 * @{ 45 * 46 * \addtogroup array ECMA Array object built-in 47 * @{ 48 */ 49 50/** 51 * The Array object's 'isArray' routine 52 * 53 * See also: 54 * ECMA-262 v5, 15.4.3.2 55 * 56 * @return ecma value 57 * Returned value must be freed with ecma_free_value. 58 */ 59static ecma_value_t 60ecma_builtin_array_object_is_array (ecma_value_t this_arg, /**< 'this' argument */ 61 ecma_value_t arg) /**< first argument */ 62{ 63 JERRY_UNUSED (this_arg); 64 65 return ecma_is_value_array (arg); 66} /* ecma_builtin_array_object_is_array */ 67 68#if ENABLED (JERRY_ES2015) 69/** 70 * The Array object's 'from' routine 71 * 72 * See also: 73 * ECMA-262 v6, 22.1.2.1 74 * 75 * @return ecma value 76 * Returned value must be freed with ecma_free_value. 77 */ 78static ecma_value_t 79ecma_builtin_array_object_from (ecma_value_t this_arg, /**< 'this' argument */ 80 const ecma_value_t *arguments_list_p, /**< arguments list */ 81 ecma_length_t arguments_list_len) /**< number of arguments */ 82{ 83 /* 1. */ 84 ecma_value_t constructor = this_arg; 85 ecma_value_t call_this_arg = ECMA_VALUE_UNDEFINED; 86 ecma_value_t items = arguments_list_p[0]; 87 ecma_value_t mapfn = (arguments_list_len > 1) ? arguments_list_p[1] : ECMA_VALUE_UNDEFINED; 88 89 /* 2. */ 90 ecma_object_t *mapfn_obj_p = NULL; 91 92 /* 3. */ 93 if (!ecma_is_value_undefined (mapfn)) 94 { 95 /* 3.a */ 96 if (!ecma_op_is_callable (mapfn)) 97 { 98 return ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable.")); 99 } 100 101 /* 3.b */ 102 if (arguments_list_len > 2) 103 { 104 call_this_arg = arguments_list_p[2]; 105 } 106 107 /* 3.c */ 108 mapfn_obj_p = ecma_get_object_from_value (mapfn); 109 } 110 111 /* 4. */ 112 ecma_value_t using_iterator = ecma_op_get_method_by_symbol_id (items, LIT_GLOBAL_SYMBOL_ITERATOR); 113 114 /* 5. */ 115 if (ECMA_IS_VALUE_ERROR (using_iterator)) 116 { 117 return using_iterator; 118 } 119 120 ecma_value_t ret_value = ECMA_VALUE_ERROR; 121 122 /* 6. */ 123 if (!ecma_is_value_undefined (using_iterator)) 124 { 125 ecma_value_t array; 126 127 /* 6.a */ 128 if (ecma_is_constructor (constructor)) 129 { 130 ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor); 131 132 array = ecma_op_function_construct (constructor_obj_p, constructor_obj_p, NULL, 0); 133 134 if (ecma_is_value_undefined (array) || ecma_is_value_null (array)) 135 { 136 ecma_free_value (using_iterator); 137 return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert undefined or null to object")); 138 } 139 } 140 else 141 { 142 /* 6.b */ 143 array = ecma_op_create_array_object (NULL, 0, false); 144 } 145 146 /* 6.c */ 147 if (ECMA_IS_VALUE_ERROR (array)) 148 { 149 ecma_free_value (using_iterator); 150 return array; 151 } 152 153 ecma_object_t *array_obj_p = ecma_get_object_from_value (array); 154 155 /* 6.d */ 156 ecma_value_t iterator = ecma_op_get_iterator (items, using_iterator); 157 ecma_free_value (using_iterator); 158 159 /* 6.e */ 160 if (ECMA_IS_VALUE_ERROR (iterator)) 161 { 162 ecma_free_value (array); 163 return iterator; 164 } 165 166 /* 6.f */ 167 uint32_t k = 0; 168 169 /* 6.g */ 170 while (true) 171 { 172 /* 6.g.ii */ 173 ecma_value_t next = ecma_op_iterator_step (iterator); 174 175 /* 6.g.iii */ 176 if (ECMA_IS_VALUE_ERROR (next)) 177 { 178 goto iterator_cleanup; 179 } 180 181 /* 6.g.iii */ 182 if (ecma_is_value_false (next)) 183 { 184 /* 6.g.iv.1 */ 185 ecma_value_t len_value = ecma_make_uint32_value (k); 186 ecma_value_t set_status = ecma_op_object_put (array_obj_p, 187 ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH), 188 len_value, 189 true); 190 ecma_free_value (len_value); 191 192 /* 6.g.iv.2 */ 193 if (ECMA_IS_VALUE_ERROR (set_status)) 194 { 195 goto iterator_cleanup; 196 } 197 198 ecma_free_value (iterator); 199 /* 6.g.iv.3 */ 200 return array; 201 } 202 203 /* 6.g.v */ 204 ecma_value_t next_value = ecma_op_iterator_value (next); 205 206 ecma_free_value (next); 207 208 /* 6.g.vi */ 209 if (ECMA_IS_VALUE_ERROR (next_value)) 210 { 211 goto iterator_cleanup; 212 } 213 214 ecma_value_t mapped_value; 215 /* 6.g.vii */ 216 if (mapfn_obj_p != NULL) 217 { 218 /* 6.g.vii.1 */ 219 ecma_value_t args_p[2] = { next_value, ecma_make_uint32_value (k) }; 220 /* 6.g.vii.3 */ 221 mapped_value = ecma_op_function_call (mapfn_obj_p, call_this_arg, args_p, 2); 222 ecma_free_value (args_p[1]); 223 ecma_free_value (next_value); 224 225 /* 6.g.vii.2 */ 226 if (ECMA_IS_VALUE_ERROR (mapped_value)) 227 { 228 ecma_op_iterator_close (iterator); 229 goto iterator_cleanup; 230 } 231 } 232 else 233 { 234 /* 6.g.viii */ 235 mapped_value = next_value; 236 } 237 238 /* 6.g.ix */ 239 const uint32_t flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW; 240 ecma_value_t set_status = ecma_builtin_helper_def_prop_by_index (array_obj_p, k, mapped_value, flags); 241 242 ecma_free_value (mapped_value); 243 244 /* 6.g.x */ 245 if (ECMA_IS_VALUE_ERROR (set_status)) 246 { 247 ecma_op_iterator_close (iterator); 248 goto iterator_cleanup; 249 } 250 251 /* 6.g.xi */ 252 k++; 253 } 254 255iterator_cleanup: 256 ecma_free_value (iterator); 257 ecma_free_value (array); 258 259 return ret_value; 260 } 261 262 /* 8. */ 263 ecma_value_t array_like = ecma_op_to_object (items); 264 265 /* 9. */ 266 if (ECMA_IS_VALUE_ERROR (array_like)) 267 { 268 return array_like; 269 } 270 271 ecma_object_t *array_like_obj_p = ecma_get_object_from_value (array_like); 272 273 /* 10. */ 274 uint32_t len; 275 ecma_value_t len_value = ecma_op_object_get_length (array_like_obj_p, &len); 276 277 /* 11. */ 278 if (ECMA_IS_VALUE_ERROR (len_value)) 279 { 280 goto cleanup; 281 } 282 283 len_value = ecma_make_uint32_value (len); 284 285 /* 12. */ 286 ecma_value_t array; 287 288 /* 12.a */ 289 if (ecma_is_constructor (constructor)) 290 { 291 ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor); 292 293 array = ecma_op_function_construct (constructor_obj_p, constructor_obj_p, &len_value, 1); 294 295 if (ecma_is_value_undefined (array) || ecma_is_value_null (array)) 296 { 297 ecma_free_value (len_value); 298 ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert undefined or null to object")); 299 goto cleanup; 300 } 301 } 302 else 303 { 304 /* 13.a */ 305 array = ecma_op_create_array_object (&len_value, 1, true); 306 } 307 308 ecma_free_value (len_value); 309 310 /* 14. */ 311 if (ECMA_IS_VALUE_ERROR (array)) 312 { 313 goto cleanup; 314 } 315 316 ecma_object_t *array_obj_p = ecma_get_object_from_value (array); 317 318 /* 15. */ 319 uint32_t k = 0; 320 321 /* 16. */ 322 while (k < len) 323 { 324 /* 16.b */ 325 ecma_value_t k_value = ecma_op_object_get_by_uint32_index (array_like_obj_p, k); 326 327 /* 16.c */ 328 if (ECMA_IS_VALUE_ERROR (k_value)) 329 { 330 goto construct_cleanup; 331 } 332 333 ecma_value_t mapped_value; 334 /* 16.d */ 335 if (mapfn_obj_p != NULL) 336 { 337 /* 16.d.i */ 338 ecma_value_t args_p[2] = { k_value, ecma_make_uint32_value (k) }; 339 mapped_value = ecma_op_function_call (mapfn_obj_p, call_this_arg, args_p, 2); 340 ecma_free_value (args_p[1]); 341 ecma_free_value (k_value); 342 343 /* 16.d.ii */ 344 if (ECMA_IS_VALUE_ERROR (mapped_value)) 345 { 346 goto construct_cleanup; 347 } 348 } 349 else 350 { 351 /* 16.e */ 352 mapped_value = k_value; 353 } 354 355 /* 16.f */ 356 const uint32_t flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW; 357 ecma_value_t set_status = ecma_builtin_helper_def_prop_by_index (array_obj_p, k, mapped_value, flags); 358 359 ecma_free_value (mapped_value); 360 361 /* 16.g */ 362 if (ECMA_IS_VALUE_ERROR (set_status)) 363 { 364 goto construct_cleanup; 365 } 366 367 /* 16.h */ 368 k++; 369 } 370 371 /* 17. */ 372 len_value = ecma_make_uint32_value (k); 373 ecma_value_t set_status = ecma_op_object_put (array_obj_p, 374 ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH), 375 len_value, 376 true); 377 ecma_free_value (len_value); 378 379 /* 18. */ 380 if (ECMA_IS_VALUE_ERROR (set_status)) 381 { 382 goto construct_cleanup; 383 } 384 385 /* 19. */ 386 ecma_deref_object (array_like_obj_p); 387 return ecma_make_object_value (array_obj_p); 388 389construct_cleanup: 390 ecma_deref_object (array_obj_p); 391cleanup: 392 ecma_deref_object (array_like_obj_p); 393 return ret_value; 394} /* ecma_builtin_array_object_from */ 395 396/** 397 * The Array object's 'of' routine 398 * 399 * See also: 400 * ECMA-262 v6, 22.1.2.3 401 * 402 * @return ecma value 403 * Returned value must be freed with ecma_free_value. 404 */ 405static ecma_value_t 406ecma_builtin_array_object_of (ecma_value_t this_arg, /**< 'this' argument */ 407 const ecma_value_t *arguments_list_p, /**< arguments list */ 408 ecma_length_t arguments_list_len) /**< number of arguments */ 409{ 410 if (!ecma_is_constructor (this_arg)) 411 { 412 return ecma_op_create_array_object (arguments_list_p, arguments_list_len, false); 413 } 414 415 ecma_value_t len = ecma_make_uint32_value (arguments_list_len); 416 417 ecma_value_t ret_val = ecma_op_function_construct (ecma_get_object_from_value (this_arg), 418 ecma_get_object_from_value (this_arg), 419 &len, 420 1); 421 422 if (ECMA_IS_VALUE_ERROR (ret_val)) 423 { 424 ecma_free_value (len); 425 return ret_val; 426 } 427 428 uint32_t k = 0; 429 ecma_object_t *obj_p = ecma_get_object_from_value (ret_val); 430 const uint32_t prop_status_flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW; 431 432 while (k < arguments_list_len) 433 { 434 ecma_value_t define_status = ecma_builtin_helper_def_prop_by_index (obj_p, 435 k, 436 arguments_list_p[k], 437 prop_status_flags); 438 439 if (ECMA_IS_VALUE_ERROR (define_status)) 440 { 441 ecma_free_value (len); 442 ecma_deref_object (obj_p); 443 return define_status; 444 } 445 446 k++; 447 } 448 449 ret_val = ecma_op_object_put (obj_p, 450 ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH), 451 len, 452 true); 453 454 ecma_free_value (len); 455 456 if (ECMA_IS_VALUE_ERROR (ret_val)) 457 { 458 ecma_deref_object (obj_p); 459 return ret_val; 460 } 461 462 return ecma_make_object_value (obj_p); 463} /* ecma_builtin_array_object_of */ 464 465/** 466 * 22.1.2.5 get Array [ @@species ] accessor 467 * 468 * @return ecma_value 469 * returned value must be freed with ecma_free_value 470 */ 471ecma_value_t 472ecma_builtin_array_species_get (ecma_value_t this_value) /**< This Value */ 473{ 474 return ecma_copy_value (this_value); 475} /* ecma_builtin_array_species_get */ 476#endif /* ENABLED (JERRY_ES2015) */ 477 478/** 479 * Handle calling [[Call]] of built-in Array object 480 * 481 * @return ecma value 482 */ 483ecma_value_t 484ecma_builtin_array_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ 485 ecma_length_t arguments_list_len) /**< number of arguments */ 486{ 487 JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); 488 489 return ecma_op_create_array_object (arguments_list_p, arguments_list_len, true); 490} /* ecma_builtin_array_dispatch_call */ 491 492/** 493 * Handle calling [[Construct]] of built-in Array object 494 * 495 * @return ecma value 496 */ 497ecma_value_t 498ecma_builtin_array_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ 499 ecma_length_t arguments_list_len) /**< number of arguments */ 500{ 501 JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); 502 503#if !ENABLED (JERRY_ES2015) 504 return ecma_op_create_array_object (arguments_list_p, arguments_list_len, true); 505#else /* ENABLED (JERRY_ES2015) */ 506 ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target), 507 ECMA_BUILTIN_ID_ARRAY_PROTOTYPE); 508 509 if (proto_p == NULL) 510 { 511 return ECMA_VALUE_ERROR; 512 } 513 514 ecma_value_t result = ecma_op_create_array_object (arguments_list_p, arguments_list_len, true); 515 516 if (ECMA_IS_VALUE_ERROR (result)) 517 { 518 ecma_deref_object (proto_p); 519 return ECMA_VALUE_ERROR; 520 } 521 522 ecma_object_t *object_p = ecma_get_object_from_value (result); 523 ECMA_SET_NON_NULL_POINTER (object_p->u2.prototype_cp, proto_p); 524 ecma_deref_object (proto_p); 525 return result; 526#endif /* ENABLED (JERRY_ES2015) */ 527} /* ecma_builtin_array_dispatch_construct */ 528 529/** 530 * @} 531 * @} 532 * @} 533 */ 534 535#endif /* ENABLED (JERRY_BUILTIN_ARRAY) */ 536