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#include "jcontext.h" 16#include "ecma-alloc.h" 17#include "ecma-array-object.h" 18#include "ecma-builtins.h" 19#include "ecma-builtin-helpers.h" 20#include "ecma-exceptions.h" 21#include "ecma-function-object.h" 22#include "ecma-gc.h" 23#include "ecma-helpers.h" 24#include "ecma-iterator-object.h" 25#include "ecma-container-object.h" 26#include "ecma-property-hashmap.h" 27#include "ecma-objects.h" 28 29#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) 30 31/** \addtogroup ecma ECMA 32 * @{ 33 * 34 * \addtogroup \addtogroup ecmamaphelpers ECMA builtin Map/Set helper functions 35 * @{ 36 */ 37 38/** 39 * Create a new internal buffer. 40 * 41 * Note: 42 * The first element of the collection tracks the size of the buffer. 43 * ECMA_VALUE_EMPTY values are not calculated into the size. 44 * 45 * @return pointer to the internal buffer 46 */ 47static inline ecma_collection_t * 48ecma_op_create_internal_buffer (void) 49{ 50 ecma_collection_t *collection_p = ecma_new_collection (); 51 ecma_collection_push_back (collection_p, (ecma_value_t) 0); 52 53 return collection_p; 54} /* ecma_op_create_internal_buffer */ 55 56/** 57 * Append values to the internal buffer. 58 */ 59static void 60ecma_op_internal_buffer_append (ecma_collection_t *container_p, /**< internal container pointer */ 61 ecma_value_t key_arg, /**< key argument */ 62 ecma_value_t value_arg, /**< value argument */ 63 lit_magic_string_id_t lit_id) /**< class id */ 64{ 65 JERRY_ASSERT (container_p != NULL); 66 67 if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) 68 { 69 ecma_value_t values[] = { ecma_copy_value_if_not_object (key_arg), ecma_copy_value_if_not_object (value_arg) }; 70 ecma_collection_append (container_p, values, 2); 71 } 72 else 73 { 74 ecma_collection_push_back (container_p, ecma_copy_value_if_not_object (key_arg)); 75 } 76 77 ECMA_CONTAINER_SET_SIZE (container_p, ECMA_CONTAINER_GET_SIZE (container_p) + 1); 78} /* ecma_op_internal_buffer_append */ 79 80/** 81 * Update the value of a given entry. 82 */ 83static inline void 84ecma_op_internal_buffer_update (ecma_value_t *entry_p, /**< entry pointer */ 85 ecma_value_t value_arg, /**< value argument */ 86 lit_magic_string_id_t lit_id) /**< class id */ 87{ 88 JERRY_ASSERT (entry_p != NULL); 89 90 if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) 91 { 92 ecma_free_value_if_not_object (((ecma_container_pair_t *) entry_p)->value); 93 94 ((ecma_container_pair_t *) entry_p)->value = ecma_copy_value_if_not_object (value_arg); 95 } 96} /* ecma_op_internal_buffer_update */ 97 98/** 99 * Delete element from the internal buffer. 100 */ 101static void 102ecma_op_internal_buffer_delete (ecma_collection_t *container_p, /**< internal container pointer */ 103 ecma_container_pair_t *entry_p, /**< entry pointer */ 104 lit_magic_string_id_t lit_id) /**< class id */ 105{ 106 JERRY_ASSERT (container_p != NULL); 107 JERRY_ASSERT (entry_p != NULL); 108 109 ecma_free_value_if_not_object (entry_p->key); 110 entry_p->key = ECMA_VALUE_EMPTY; 111 112 if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) 113 { 114 ecma_free_value_if_not_object (entry_p->value); 115 entry_p->value = ECMA_VALUE_EMPTY; 116 } 117 118 ECMA_CONTAINER_SET_SIZE (container_p, ECMA_CONTAINER_GET_SIZE (container_p) - 1); 119} /* ecma_op_internal_buffer_delete */ 120 121/** 122 * Find an entry in the collection. 123 * 124 * @return pointer to the appropriate entry. 125 */ 126static ecma_value_t * 127ecma_op_internal_buffer_find (ecma_collection_t *container_p, /**< internal container pointer */ 128 ecma_value_t key_arg, /**< key argument */ 129 lit_magic_string_id_t lit_id) /**< class id */ 130{ 131 JERRY_ASSERT (container_p != NULL); 132 133 uint8_t entry_size = ecma_op_container_entry_size (lit_id); 134 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); 135 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); 136 137 for (uint32_t i = 0; i < entry_count; i += entry_size) 138 { 139 ecma_value_t *entry_p = start_p + i; 140 141 if (ecma_op_same_value_zero (*entry_p, key_arg)) 142 { 143 return entry_p; 144 } 145 } 146 147 return NULL; 148} /* ecma_op_internal_buffer_find */ 149 150/** 151 * Get the value that belongs to the key. 152 * 153 * Note: in case of Set containers, the values are the same as the keys. 154 * 155 * @return ecma value 156 */ 157static ecma_value_t 158ecma_op_container_get_value (ecma_value_t *entry_p, /**< entry (key) pointer */ 159 lit_magic_string_id_t lit_id) /**< class id */ 160{ 161 JERRY_ASSERT (entry_p != NULL); 162 163 if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) 164 { 165 return ((ecma_container_pair_t *) entry_p)->value; 166 } 167 168 return *entry_p; 169} /* ecma_op_container_get_value */ 170 171/** 172 * Get the size (in ecma_value_t) of the stored entries. 173 * 174 * @return size of the entries. 175 */ 176uint8_t 177ecma_op_container_entry_size (lit_magic_string_id_t lit_id) /**< class id */ 178{ 179 if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) 180 { 181 return ECMA_CONTAINER_PAIR_SIZE; 182 } 183 184 return ECMA_CONTAINER_VALUE_SIZE; 185} /* ecma_op_container_entry_size */ 186 187#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) 188/** 189 * Release the entries in the WeakSet container. 190 */ 191static void 192ecma_op_container_free_weakset_entries (ecma_object_t *object_p, /**< object pointer */ 193 ecma_collection_t *container_p) /** internal buffer pointer */ 194{ 195 JERRY_ASSERT (object_p != NULL); 196 JERRY_ASSERT (container_p != NULL); 197 198 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); 199 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); 200 201 for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_VALUE_SIZE) 202 { 203 ecma_value_t *entry_p = start_p + i; 204 205 if (ecma_is_value_empty (*entry_p)) 206 { 207 continue; 208 } 209 210 ecma_op_container_unref_weak (ecma_get_object_from_value (*entry_p), ecma_make_object_value (object_p)); 211 ecma_op_container_remove_weak_entry (object_p, *entry_p); 212 213 *entry_p = ECMA_VALUE_EMPTY; 214 } 215} /* ecma_op_container_free_weakset_entries */ 216#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ 217 218#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) 219/** 220 * Release the entries in the WeakMap container. 221 */ 222static void 223ecma_op_container_free_weakmap_entries (ecma_object_t *object_p, /**< object pointer */ 224 ecma_collection_t *container_p) /**< internal buffer pointer */ 225{ 226 JERRY_ASSERT (object_p != NULL); 227 JERRY_ASSERT (container_p != NULL); 228 229 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); 230 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); 231 232 for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_PAIR_SIZE) 233 { 234 ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i); 235 236 if (ecma_is_value_empty (entry_p->key)) 237 { 238 continue; 239 } 240 241 ecma_op_container_unref_weak (ecma_get_object_from_value (entry_p->key), ecma_make_object_value (object_p)); 242 ecma_op_container_remove_weak_entry (object_p, entry_p->key); 243 244 ecma_free_value_if_not_object (entry_p->value); 245 246 entry_p->key = ECMA_VALUE_EMPTY; 247 entry_p->value = ECMA_VALUE_EMPTY; 248 } 249} /* ecma_op_container_free_weakmap_entries */ 250#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ 251 252#if ENABLED (JERRY_ES2015_BUILTIN_SET) 253/** 254 * Release the entries in the Set container. 255 */ 256static void 257ecma_op_container_free_set_entries (ecma_collection_t *container_p) 258{ 259 JERRY_ASSERT (container_p != NULL); 260 261 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); 262 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); 263 264 for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_VALUE_SIZE) 265 { 266 ecma_value_t *entry_p = start_p + i; 267 268 if (ecma_is_value_empty (*entry_p)) 269 { 270 continue; 271 } 272 273 ecma_free_value_if_not_object (*entry_p); 274 *entry_p = ECMA_VALUE_EMPTY; 275 } 276} /* ecma_op_container_free_set_entries */ 277#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ 278 279#if ENABLED (JERRY_ES2015_BUILTIN_MAP) 280/** 281 * Release the entries in the Map container. 282 */ 283static void 284ecma_op_container_free_map_entries (ecma_collection_t *container_p) 285{ 286 JERRY_ASSERT (container_p != NULL); 287 288 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); 289 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); 290 291 for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_PAIR_SIZE) 292 { 293 ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i); 294 295 if (ecma_is_value_empty (entry_p->key)) 296 { 297 continue; 298 } 299 300 ecma_free_value_if_not_object (entry_p->key); 301 ecma_free_value_if_not_object (entry_p->value); 302 303 entry_p->key = ECMA_VALUE_EMPTY; 304 entry_p->value = ECMA_VALUE_EMPTY; 305 } 306} /* ecma_op_container_free_map_entries */ 307#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ 308 309/** 310 * Release the internal buffer and the stored entries. 311 */ 312void 313ecma_op_container_free_entries (ecma_object_t *object_p) /**< collection object pointer */ 314{ 315 JERRY_ASSERT (object_p != NULL); 316 317 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; 318 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 319 map_object_p->u.class_prop.u.value); 320 321 switch (map_object_p->u.class_prop.class_id) 322 { 323#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) 324 case LIT_MAGIC_STRING_WEAKSET_UL: 325 { 326 ecma_op_container_free_weakset_entries (object_p, container_p); 327 break; 328 } 329#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ 330#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) 331 case LIT_MAGIC_STRING_WEAKMAP_UL: 332 { 333 ecma_op_container_free_weakmap_entries (object_p, container_p); 334 break; 335 } 336#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ 337#if ENABLED (JERRY_ES2015_BUILTIN_SET) 338 case LIT_MAGIC_STRING_SET_UL: 339 { 340 ecma_op_container_free_set_entries (container_p); 341 break; 342 } 343#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ 344#if ENABLED (JERRY_ES2015_BUILTIN_MAP) 345 case LIT_MAGIC_STRING_MAP_UL: 346 { 347 ecma_op_container_free_map_entries (container_p); 348 break; 349 } 350#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ 351 default: 352 { 353 break; 354 } 355 } 356 357 ECMA_CONTAINER_SET_SIZE (container_p, 0); 358} /* ecma_op_container_free_entries */ 359 360/** 361 * Handle calling [[Construct]] of built-in Map/Set like objects 362 * 363 * @return ecma value 364 */ 365ecma_value_t 366ecma_op_container_create (const ecma_value_t *arguments_list_p, /**< arguments list */ 367 ecma_length_t arguments_list_len, /**< number of arguments */ 368 lit_magic_string_id_t lit_id, /**< internal class id */ 369 ecma_builtin_id_t proto_id) /**< prototype builtin id */ 370{ 371 JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); 372 JERRY_ASSERT (lit_id == LIT_MAGIC_STRING_MAP_UL 373 || lit_id == LIT_MAGIC_STRING_SET_UL 374 || lit_id == LIT_MAGIC_STRING_WEAKMAP_UL 375 || lit_id == LIT_MAGIC_STRING_WEAKSET_UL); 376 JERRY_ASSERT (JERRY_CONTEXT (current_new_target) != NULL); 377 378 ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target), proto_id); 379 380 if (JERRY_UNLIKELY (proto_p == NULL)) 381 { 382 return ECMA_VALUE_ERROR; 383 } 384 385 ecma_collection_t *container_p = ecma_op_create_internal_buffer (); 386 ecma_object_t *object_p = ecma_create_object (proto_p, 387 sizeof (ecma_extended_object_t), 388 ECMA_OBJECT_TYPE_CLASS); 389 ecma_deref_object (proto_p); 390 ecma_extended_object_t *map_obj_p = (ecma_extended_object_t *) object_p; 391 map_obj_p->u.class_prop.extra_info = ECMA_CONTAINER_FLAGS_EMPTY; 392 map_obj_p->u.class_prop.class_id = (uint16_t) lit_id; 393 394 if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL) 395 { 396 map_obj_p->u.class_prop.extra_info |= ECMA_CONTAINER_FLAGS_WEAK; 397 } 398 399 ECMA_SET_INTERNAL_VALUE_POINTER (map_obj_p->u.class_prop.u.value, container_p); 400 401 ecma_value_t set_value = ecma_make_object_value (object_p); 402 ecma_value_t result = set_value; 403 404#if ENABLED (JERRY_ES2015) 405 if (arguments_list_len == 0) 406 { 407 return result; 408 } 409 410 ecma_value_t iterable = arguments_list_p[0]; 411 412 if (ecma_is_value_undefined (iterable) || ecma_is_value_null (iterable)) 413 { 414 return result; 415 } 416 417 lit_magic_string_id_t adder_string_id; 418 if (lit_id == LIT_MAGIC_STRING_MAP_UL || lit_id == LIT_MAGIC_STRING_WEAKMAP_UL) 419 { 420 adder_string_id = LIT_MAGIC_STRING_SET; 421 } 422 else 423 { 424 adder_string_id = LIT_MAGIC_STRING_ADD; 425 } 426 427 result = ecma_op_object_get_by_magic_id (object_p, adder_string_id); 428 if (ECMA_IS_VALUE_ERROR (result)) 429 { 430 goto cleanup_object; 431 } 432 433 if (!ecma_op_is_callable (result)) 434 { 435 ecma_free_value (result); 436 result = ecma_raise_type_error (ECMA_ERR_MSG ("add/set function is not callable.")); 437 goto cleanup_object; 438 } 439 440 ecma_object_t *adder_func_p = ecma_get_object_from_value (result); 441 442 result = ecma_op_get_iterator (iterable, ECMA_VALUE_EMPTY); 443 444 if (ECMA_IS_VALUE_ERROR (result)) 445 { 446 goto cleanup_adder; 447 } 448 449 const ecma_value_t iter = result; 450 451 while (true) 452 { 453 result = ecma_op_iterator_step (iter); 454 455 if (ECMA_IS_VALUE_ERROR (result)) 456 { 457 goto cleanup_iter; 458 } 459 460 if (ecma_is_value_false (result)) 461 { 462 break; 463 } 464 465 const ecma_value_t next = result; 466 result = ecma_op_iterator_value (next); 467 ecma_free_value (next); 468 469 if (ECMA_IS_VALUE_ERROR (result)) 470 { 471 goto cleanup_iter; 472 } 473 474 if (lit_id == LIT_MAGIC_STRING_SET_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL) 475 { 476 const ecma_value_t value = result; 477 478 ecma_value_t arguments[] = { value }; 479 result = ecma_op_function_call (adder_func_p, set_value, arguments, 1); 480 481 ecma_free_value (value); 482 } 483 else 484 { 485 if (!ecma_is_value_object (result)) 486 { 487 ecma_free_value (result); 488 ecma_raise_type_error (ECMA_ERR_MSG ("Iterator value is not an object.")); 489 result = ecma_op_iterator_close (iter); 490 JERRY_ASSERT (ECMA_IS_VALUE_ERROR (result)); 491 goto cleanup_iter; 492 } 493 494 ecma_object_t *next_object_p = ecma_get_object_from_value (result); 495 496 result = ecma_op_object_get_by_uint32_index (next_object_p, 0); 497 498 if (ECMA_IS_VALUE_ERROR (result)) 499 { 500 ecma_deref_object (next_object_p); 501 ecma_op_iterator_close (iter); 502 goto cleanup_iter; 503 } 504 505 const ecma_value_t key = result; 506 507 result = ecma_op_object_get_by_uint32_index (next_object_p, 1); 508 509 if (ECMA_IS_VALUE_ERROR (result)) 510 { 511 ecma_deref_object (next_object_p); 512 ecma_free_value (key); 513 ecma_op_iterator_close (iter); 514 goto cleanup_iter; 515 } 516 517 const ecma_value_t value = result; 518 ecma_value_t arguments[] = { key, value }; 519 result = ecma_op_function_call (adder_func_p, set_value, arguments, 2); 520 521 ecma_free_value (key); 522 ecma_free_value (value); 523 ecma_deref_object (next_object_p); 524 } 525 526 if (ECMA_IS_VALUE_ERROR (result)) 527 { 528 ecma_op_iterator_close (iter); 529 goto cleanup_iter; 530 } 531 532 ecma_free_value (result); 533 } 534 535 ecma_free_value (iter); 536 ecma_deref_object (adder_func_p); 537 return ecma_make_object_value (object_p); 538 539cleanup_iter: 540 ecma_free_value (iter); 541cleanup_adder: 542 ecma_deref_object (adder_func_p); 543cleanup_object: 544 ecma_deref_object (object_p); 545#endif /* ENABLED (JERRY_ES2015) */ 546 547 return result; 548} /* ecma_op_container_create */ 549 550/** 551 * Get Map/Set object pointer 552 * 553 * Note: 554 * If the function returns with NULL, the error object has 555 * already set, and the caller must return with ECMA_VALUE_ERROR 556 * 557 * @return pointer to the Map/Set if this_arg is a valid Map/Set object 558 * NULL otherwise 559 */ 560static ecma_extended_object_t * 561ecma_op_container_get_object (ecma_value_t this_arg, /**< this argument */ 562 lit_magic_string_id_t lit_id) /**< internal class id */ 563{ 564 if (ecma_is_value_object (this_arg)) 565 { 566 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) ecma_get_object_from_value (this_arg); 567 568 if (ecma_get_object_type ((ecma_object_t *) map_object_p) == ECMA_OBJECT_TYPE_CLASS 569 && map_object_p->u.class_prop.class_id == lit_id) 570 { 571 return map_object_p; 572 } 573 } 574 575#if ENABLED (JERRY_ERROR_MESSAGES) 576 ecma_raise_standard_error_with_format (ECMA_ERROR_TYPE, 577 "Expected a % object.", 578 ecma_make_string_value (ecma_get_magic_string (lit_id))); 579#else /* !ENABLED (JERRY_ERROR_MESSAGES) */ 580 ecma_raise_type_error (NULL); 581#endif /* ENABLED (JERRY_ERROR_MESSAGES) */ 582 583 return NULL; 584} /* ecma_op_container_get_object */ 585 586/** 587 * Returns with the size of the Map/Set object. 588 * 589 * @return size of the Map/Set object as ecma-value. 590 */ 591ecma_value_t 592ecma_op_container_size (ecma_value_t this_arg, /**< this argument */ 593 lit_magic_string_id_t lit_id) /**< internal class id */ 594{ 595 ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); 596 597 if (map_object_p == NULL) 598 { 599 return ECMA_VALUE_ERROR; 600 } 601 602 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 603 map_object_p->u.class_prop.u.value); 604 605 return ecma_make_uint32_value (ECMA_CONTAINER_GET_SIZE (container_p)); 606} /* ecma_op_container_size */ 607 608/** 609 * The generic Map/WeakMap prototype object's 'get' routine 610 * 611 * @return ecma value 612 * Returned value must be freed with ecma_free_value. 613 */ 614ecma_value_t 615ecma_op_container_get (ecma_value_t this_arg, /**< this argument */ 616 ecma_value_t key_arg, /**< key argument */ 617 lit_magic_string_id_t lit_id) /**< internal class id */ 618{ 619 ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); 620 621 if (map_object_p == NULL) 622 { 623 return ECMA_VALUE_ERROR; 624 } 625 626#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) 627 if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL && !ecma_is_value_object (key_arg)) 628 { 629 return ECMA_VALUE_UNDEFINED; 630 } 631#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ 632 633 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 634 map_object_p->u.class_prop.u.value); 635 636 if (ECMA_CONTAINER_GET_SIZE (container_p) == 0) 637 { 638 return ECMA_VALUE_UNDEFINED; 639 } 640 641 ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); 642 643 if (entry_p == NULL) 644 { 645 return ECMA_VALUE_UNDEFINED; 646 } 647 648 return ecma_copy_value (((ecma_container_pair_t *) entry_p)->value); 649} /* ecma_op_container_get */ 650 651/** 652 * The generic Map/Set prototype object's 'has' routine 653 * 654 * @return ecma value 655 * Returned value must be freed with ecma_free_value. 656 */ 657ecma_value_t 658ecma_op_container_has (ecma_value_t this_arg, /**< this argument */ 659 ecma_value_t key_arg, /**< key argument */ 660 lit_magic_string_id_t lit_id) /**< internal class id */ 661{ 662 ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); 663 664 if (map_object_p == NULL) 665 { 666 return ECMA_VALUE_ERROR; 667 } 668 669 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 670 map_object_p->u.class_prop.u.value); 671 672#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) 673 if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0 674 && !ecma_is_value_object (key_arg)) 675 { 676 return ECMA_VALUE_FALSE; 677 } 678#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ 679 680 if (ECMA_CONTAINER_GET_SIZE (container_p) == 0) 681 { 682 return ECMA_VALUE_FALSE; 683 } 684 685 ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); 686 687 return ecma_make_boolean_value (entry_p != NULL); 688} /* ecma_op_container_has */ 689 690/** 691 * Set a weak reference from a container to a key object 692 */ 693static void 694ecma_op_container_set_weak (ecma_object_t *const key_p, /**< key object */ 695 ecma_extended_object_t *const container_p) /**< container */ 696{ 697 if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (key_p))) 698 { 699 ecma_fast_array_convert_to_normal (key_p); 700 } 701 702 ecma_string_t *weak_refs_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS); 703 ecma_property_t *property_p = ecma_find_named_property (key_p, weak_refs_string_p); 704 ecma_collection_t *refs_p; 705 706 if (property_p == NULL) 707 { 708 ecma_property_value_t *value_p = ecma_create_named_data_property (key_p, 709 weak_refs_string_p, 710 ECMA_PROPERTY_CONFIGURABLE_WRITABLE, 711 &property_p); 712 ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p); 713 refs_p = ecma_new_collection (); 714 ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, refs_p); 715 } 716 else 717 { 718 refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, (ECMA_PROPERTY_VALUE_PTR (property_p)->value)); 719 } 720 721 const ecma_value_t container_value = ecma_make_object_value ((ecma_object_t *) container_p); 722 for (uint32_t i = 0; i < refs_p->item_count; i++) 723 { 724 if (ecma_is_value_empty (refs_p->buffer_p[i])) 725 { 726 refs_p->buffer_p[i] = container_value; 727 return; 728 } 729 } 730 731 ecma_collection_push_back (refs_p, container_value); 732} /* ecma_op_container_set_weak */ 733 734/** 735 * Helper method for the Map.prototype.set and Set.prototype.add methods to swap the sign of the given value if needed 736 * 737 * See also: 738 * ECMA-262 v6, 23.2.3.1 step 6 739 * ECMA-262 v6, 23.1.3.9 step 6 740 * 741 * @return ecma value 742 */ 743static ecma_value_t 744ecma_op_container_set_noramlize_zero (ecma_value_t this_arg) /*< this arg */ 745{ 746 if (ecma_is_value_number (this_arg)) 747 { 748 ecma_number_t number_value = ecma_get_number_from_value (this_arg); 749 750 if (JERRY_UNLIKELY (ecma_number_is_zero (number_value) && ecma_number_is_negative (number_value))) 751 { 752 return ecma_make_integer_value (0); 753 } 754 } 755 756 return this_arg; 757} /* ecma_op_container_set_noramlize_zero */ 758 759/** 760 * The generic Map prototype object's 'set' and Set prototype object's 'add' routine 761 * 762 * @return ecma value 763 * Returned value must be freed with ecma_free_value. 764 */ 765ecma_value_t 766ecma_op_container_set (ecma_value_t this_arg, /**< this argument */ 767 ecma_value_t key_arg, /**< key argument */ 768 ecma_value_t value_arg, /**< value argument */ 769 lit_magic_string_id_t lit_id) /**< internal class id */ 770{ 771 ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); 772 773 if (map_object_p == NULL) 774 { 775 return ECMA_VALUE_ERROR; 776 } 777 778 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 779 map_object_p->u.class_prop.u.value); 780 781#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) 782 if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0 783 && !ecma_is_value_object (key_arg)) 784 { 785 return ecma_raise_type_error (ECMA_ERR_MSG ("Key must be an object")); 786 } 787#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ 788 789 ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); 790 791 if (entry_p == NULL) 792 { 793 ecma_op_internal_buffer_append (container_p, 794 ecma_op_container_set_noramlize_zero (key_arg), 795 value_arg, 796 lit_id); 797 798#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) 799 if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0) 800 { 801 ecma_object_t *key_p = ecma_get_object_from_value (key_arg); 802 ecma_op_container_set_weak (key_p, map_object_p); 803 } 804#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ 805 } 806 else 807 { 808 ecma_op_internal_buffer_update (entry_p, ecma_op_container_set_noramlize_zero (value_arg), lit_id); 809 } 810 811 ecma_ref_object ((ecma_object_t *) map_object_p); 812 return this_arg; 813} /* ecma_op_container_set */ 814 815/** 816 * The generic Map/Set prototype object's 'forEach' routine 817 * 818 * @return ecma value 819 * Returned value must be freed with ecma_free_value. 820 */ 821ecma_value_t 822ecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */ 823 ecma_value_t predicate, /**< callback function */ 824 ecma_value_t predicate_this_arg, /**< this argument for 825 * invoke predicate */ 826 lit_magic_string_id_t lit_id) /**< internal class id */ 827{ 828 ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); 829 830 if (map_object_p == NULL) 831 { 832 return ECMA_VALUE_ERROR; 833 } 834 835 if (!ecma_op_is_callable (predicate)) 836 { 837 return ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable.")); 838 } 839 840 JERRY_ASSERT (ecma_is_value_object (predicate)); 841 ecma_object_t *func_object_p = ecma_get_object_from_value (predicate); 842 ecma_value_t ret_value = ECMA_VALUE_UNDEFINED; 843 844 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 845 map_object_p->u.class_prop.u.value); 846 847 uint8_t entry_size = ecma_op_container_entry_size (lit_id); 848 849 for (uint32_t i = 0; i < ECMA_CONTAINER_ENTRY_COUNT (container_p); i += entry_size) 850 { 851 ecma_value_t *entry_p = ECMA_CONTAINER_START (container_p) + i; 852 853 if (ecma_is_value_empty (*entry_p)) 854 { 855 continue; 856 } 857 858 ecma_value_t key_arg = *entry_p; 859 ecma_value_t value_arg = ecma_op_container_get_value (entry_p, lit_id); 860 861 ecma_value_t call_args[] = { value_arg, key_arg, this_arg }; 862 ecma_value_t call_value = ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 3); 863 864 if (ECMA_IS_VALUE_ERROR (call_value)) 865 { 866 ret_value = call_value; 867 break; 868 } 869 870 ecma_free_value (call_value); 871 } 872 873 return ret_value; 874} /* ecma_op_container_foreach */ 875 876/** 877 * The Map/Set prototype object's 'clear' routine 878 * 879 * @return ecma value 880 * Returned value must be freed with ecma_free_value. 881 */ 882ecma_value_t 883ecma_op_container_clear (ecma_value_t this_arg, /**< this argument */ 884 lit_magic_string_id_t lit_id) /**< internal class id */ 885{ 886 ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); 887 888 if (map_object_p == NULL) 889 { 890 return ECMA_VALUE_ERROR; 891 } 892 893 ecma_op_container_free_entries ((ecma_object_t *) map_object_p); 894 895 return ECMA_VALUE_UNDEFINED; 896} /* ecma_op_container_clear */ 897 898/** 899 * The generic Map/Set prototype object's 'delete' routine 900 * 901 * @return ecma value 902 * Returned value must be freed with ecma_free_value. 903 */ 904ecma_value_t 905ecma_op_container_delete (ecma_value_t this_arg, /**< this argument */ 906 ecma_value_t key_arg, /**< key argument */ 907 lit_magic_string_id_t lit_id) /**< internal class id */ 908{ 909 ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); 910 911 if (map_object_p == NULL) 912 { 913 return ECMA_VALUE_ERROR; 914 } 915 916 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 917 map_object_p->u.class_prop.u.value); 918 919 ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); 920 921 if (entry_p == NULL) 922 { 923 return ECMA_VALUE_FALSE; 924 } 925 926 ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, lit_id); 927 return ECMA_VALUE_TRUE; 928} /* ecma_op_container_delete */ 929 930/** 931 * The generic WeakMap/WeakSet prototype object's 'delete' routine 932 * 933 * @return ecma value 934 * Returned value must be freed with ecma_free_value. 935 */ 936ecma_value_t 937ecma_op_container_delete_weak (ecma_value_t this_arg, /**< this argument */ 938 ecma_value_t key_arg, /**< key argument */ 939 lit_magic_string_id_t lit_id) /**< internal class id */ 940{ 941 ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); 942 943 if (map_object_p == NULL) 944 { 945 return ECMA_VALUE_ERROR; 946 } 947 948 if (!ecma_is_value_object (key_arg)) 949 { 950 return ECMA_VALUE_FALSE; 951 } 952 953 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 954 map_object_p->u.class_prop.u.value); 955 956 ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); 957 958 if (entry_p == NULL) 959 { 960 return ECMA_VALUE_FALSE; 961 } 962 963 ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, lit_id); 964 965 ecma_object_t *key_object_p = ecma_get_object_from_value (key_arg); 966 ecma_op_container_unref_weak (key_object_p, ecma_make_object_value ((ecma_object_t *) map_object_p)); 967 968 return ECMA_VALUE_TRUE; 969} /* ecma_op_container_delete_weak */ 970 971/** 972 * Helper function to remove a weak reference to an object. 973 * 974 * @return ecma value 975 * Returned value must be freed with ecma_free_value. 976 */ 977void 978ecma_op_container_unref_weak (ecma_object_t *object_p, /**< this argument */ 979 ecma_value_t ref_holder) /**< key argument */ 980{ 981 ecma_string_t *weak_refs_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS); 982 983 ecma_property_t *property_p = ecma_find_named_property (object_p, weak_refs_string_p); 984 JERRY_ASSERT (property_p != NULL); 985 986 ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 987 ECMA_PROPERTY_VALUE_PTR (property_p)->value); 988 for (uint32_t i = 0; i < refs_p->item_count; i++) 989 { 990 if (refs_p->buffer_p[i] == ref_holder) 991 { 992 refs_p->buffer_p[i] = ECMA_VALUE_EMPTY; 993 break; 994 } 995 } 996} /* ecma_op_container_unref_weak */ 997 998/** 999 * Helper function to remove a key/value pair from a weak container object 1000 */ 1001void 1002ecma_op_container_remove_weak_entry (ecma_object_t *object_p, /**< internal container object */ 1003 ecma_value_t key_arg) /**< key */ 1004{ 1005 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; 1006 1007 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 1008 map_object_p->u.class_prop.u.value); 1009 1010 ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, map_object_p->u.class_prop.class_id); 1011 1012 JERRY_ASSERT (entry_p != NULL); 1013 1014 ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, map_object_p->u.class_prop.class_id); 1015} /* ecma_op_container_remove_weak_entry */ 1016 1017#if ENABLED (JERRY_ES2015) 1018 1019/** 1020 * The Create{Set, Map}Iterator Abstract operation 1021 * 1022 * See also: 1023 * ECMA-262 v6, 23.1.5.1 1024 * ECMA-262 v6, 23.2.5.1 1025 * 1026 * Note: 1027 * Returned value must be freed with ecma_free_value. 1028 * 1029 * @return Map/Set iterator object, if success 1030 * error - otherwise 1031 */ 1032ecma_value_t 1033ecma_op_container_create_iterator (ecma_value_t this_arg, /**< this argument */ 1034 uint8_t type, /**< any combination of 1035 * ecma_iterator_type_t bits */ 1036 lit_magic_string_id_t lit_id, /**< internal class id */ 1037 ecma_builtin_id_t proto_id, /**< prototype builtin id */ 1038 ecma_pseudo_array_type_t iterator_type) /**< type of the iterator */ 1039{ 1040 ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); 1041 1042 if (map_object_p == NULL) 1043 { 1044 return ECMA_VALUE_ERROR; 1045 } 1046 1047 return ecma_op_create_iterator_object (this_arg, 1048 ecma_builtin_get (proto_id), 1049 (uint8_t) iterator_type, 1050 type); 1051} /* ecma_op_container_create_iterator */ 1052 1053/** 1054 * Get the index of the iterator object. 1055 * 1056 * @return index of the iterator. 1057 */ 1058static uint32_t 1059ecma_op_iterator_get_index (ecma_object_t *iter_obj_p) /**< iterator object pointer */ 1060{ 1061 uint32_t index = ((ecma_extended_object_t *) iter_obj_p)->u.pseudo_array.u1.iterator_index; 1062 1063 if (JERRY_UNLIKELY (index == ECMA_ITERATOR_INDEX_LIMIT)) 1064 { 1065 ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX); 1066 ecma_property_t *property_p = ecma_find_named_property (iter_obj_p, prop_name_p); 1067 ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p); 1068 1069 return (uint32_t) (ecma_get_number_from_value (value_p->value)); 1070 } 1071 1072 return index; 1073} /* ecma_op_iterator_get_index */ 1074 1075/** 1076 * Set the index of the iterator object. 1077 */ 1078static void 1079ecma_op_iterator_set_index (ecma_object_t *iter_obj_p, /**< iterator object pointer */ 1080 uint32_t index) /* iterator index to set */ 1081{ 1082 if (JERRY_UNLIKELY (index >= ECMA_ITERATOR_INDEX_LIMIT)) 1083 { 1084 /* After the ECMA_ITERATOR_INDEX_LIMIT limit is reached the [[%Iterator%NextIndex]] 1085 property is stored as an internal property */ 1086 ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX); 1087 ecma_property_t *property_p = ecma_find_named_property (iter_obj_p, prop_name_p); 1088 ecma_property_value_t *value_p; 1089 1090 if (property_p == NULL) 1091 { 1092 value_p = ecma_create_named_data_property (iter_obj_p, prop_name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p); 1093 value_p->value = ecma_make_uint32_value (index); 1094 } 1095 else 1096 { 1097 value_p = ECMA_PROPERTY_VALUE_PTR (property_p); 1098 value_p->value = ecma_make_uint32_value (index); 1099 } 1100 } 1101 else 1102 { 1103 ((ecma_extended_object_t *) iter_obj_p)->u.pseudo_array.u1.iterator_index = (uint16_t) index; 1104 } 1105} /* ecma_op_iterator_set_index */ 1106 1107/** 1108 * The %{Set, Map}IteratorPrototype% object's 'next' routine 1109 * 1110 * See also: 1111 * ECMA-262 v6, 23.1.5.2.1 1112 * ECMA-262 v6, 23.2.5.2.1 1113 * 1114 * Note: 1115 * Returned value must be freed with ecma_free_value. 1116 * 1117 * @return iterator result object, if success 1118 * error - otherwise 1119 */ 1120ecma_value_t 1121ecma_op_container_iterator_next (ecma_value_t this_val, /**< this argument */ 1122 ecma_pseudo_array_type_t iterator_type) /**< type of the iterator */ 1123{ 1124 if (!ecma_is_value_object (this_val)) 1125 { 1126 return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not an object.")); 1127 } 1128 1129 ecma_object_t *obj_p = ecma_get_object_from_value (this_val); 1130 ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; 1131 1132 if (ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_PSEUDO_ARRAY 1133 || ext_obj_p->u.pseudo_array.type != iterator_type) 1134 { 1135 return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not an iterator.")); 1136 } 1137 1138 ecma_value_t iterated_value = ext_obj_p->u.pseudo_array.u2.iterated_value; 1139 1140 if (ecma_is_value_empty (iterated_value)) 1141 { 1142 return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE); 1143 } 1144 1145 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) (ecma_get_object_from_value (iterated_value)); 1146 lit_magic_string_id_t lit_id = map_object_p->u.class_prop.class_id; 1147 1148 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 1149 map_object_p->u.class_prop.u.value); 1150 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); 1151 uint32_t index = ecma_op_iterator_get_index (obj_p); 1152 1153 if (index == entry_count) 1154 { 1155 ext_obj_p->u.pseudo_array.u2.iterated_value = ECMA_VALUE_EMPTY; 1156 1157 return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE); 1158 } 1159 1160 uint8_t entry_size = ecma_op_container_entry_size (lit_id); 1161 uint8_t iterator_kind = ext_obj_p->u.pseudo_array.extra_info; 1162 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); 1163 ecma_value_t ret_value = ECMA_VALUE_UNDEFINED; 1164 1165 for (uint32_t i = index; i < entry_count; i += entry_size) 1166 { 1167 ecma_value_t *entry_p = start_p + i; 1168 1169 if (ecma_is_value_empty (*entry_p)) 1170 { 1171 if (i == (entry_count - entry_size)) 1172 { 1173 ret_value = ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE); 1174 break; 1175 } 1176 1177 continue; 1178 } 1179 1180 ecma_op_iterator_set_index (obj_p, i + entry_size); 1181 1182 ecma_value_t key_arg = *entry_p; 1183 ecma_value_t value_arg = ecma_op_container_get_value (entry_p, lit_id); 1184 1185 if (iterator_kind == ECMA_ITERATOR_KEYS) 1186 { 1187 ret_value = ecma_create_iter_result_object (key_arg, ECMA_VALUE_FALSE); 1188 } 1189 else if (iterator_kind == ECMA_ITERATOR_VALUES) 1190 { 1191 ret_value = ecma_create_iter_result_object (value_arg, ECMA_VALUE_FALSE); 1192 } 1193 else 1194 { 1195 JERRY_ASSERT (iterator_kind == ECMA_ITERATOR_KEYS_VALUES); 1196 1197 ecma_value_t entry_array_value; 1198 entry_array_value = ecma_create_array_from_iter_element (value_arg, key_arg); 1199 1200 ret_value = ecma_create_iter_result_object (entry_array_value, ECMA_VALUE_FALSE); 1201 ecma_free_value (entry_array_value); 1202 } 1203 1204 break; 1205 } 1206 1207 return ret_value; 1208} /* ecma_op_container_iterator_next */ 1209 1210#endif /* ENABLED (JERRY_ES2015) */ 1211 1212/** 1213 * @} 1214 * @} 1215 */ 1216 1217#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ 1218