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/** 17 * Garbage collector implementation 18 */ 19 20#include "ecma-alloc.h" 21#include "ecma-array-object.h" 22#include "ecma-container-object.h" 23#include "ecma-function-object.h" 24#include "ecma-globals.h" 25#include "ecma-gc.h" 26#include "ecma-helpers.h" 27#include "ecma-objects.h" 28#include "ecma-property-hashmap.h" 29#include "ecma-proxy-object.h" 30#include "jcontext.h" 31#include "jrt.h" 32#include "jrt-libc-includes.h" 33#include "jrt-bit-fields.h" 34#include "re-compiler.h" 35#include "vm-defines.h" 36#include "vm-stack.h" 37 38#if defined(JERRY_HEAPDUMP) 39#include "heapdump.h" 40#endif 41 42#if defined(JERRY_REF_TRACKER) 43#include "tracker.h" 44#endif 45 46#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) 47#include "ecma-typedarray-object.h" 48#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ 49#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) 50#include "ecma-promise-object.h" 51#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ 52 53/* TODO: Extract GC to a separate component */ 54 55/** \addtogroup ecma ECMA 56 * @{ 57 * 58 * \addtogroup ecmagc Garbage collector 59 * @{ 60 */ 61 62/* 63 * The garbage collector uses the reference counter 64 * of object: it increases the counter by one when 65 * the object is marked at the first time. 66 */ 67 68/** 69 * Get visited flag of the object. 70 * 71 * @return true - if visited 72 * false - otherwise 73 */ 74static inline bool JERRY_ATTR_ALWAYS_INLINE 75ecma_gc_is_object_visited (ecma_object_t *object_p) /**< object */ 76{ 77 JERRY_ASSERT (object_p != NULL); 78 79 return (object_p->type_flags_refs < ECMA_OBJECT_NON_VISITED); 80} /* ecma_gc_is_object_visited */ 81 82/** 83 * Mark objects as visited starting from specified object as root 84 */ 85static void ecma_gc_mark (ecma_object_t *object_p); 86 87/** 88 * Set visited flag of the object. 89 */ 90static void 91ecma_gc_set_object_visited (ecma_object_t *object_p) /**< object */ 92{ 93 if (object_p->type_flags_refs >= ECMA_OBJECT_NON_VISITED) 94 { 95#if (JERRY_GC_MARK_LIMIT != 0) 96 if (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) != 0) 97 { 98 JERRY_CONTEXT (ecma_gc_mark_recursion_limit)--; 99 /* Set the reference count of gray object to 0 */ 100 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1)); 101 ecma_gc_mark (object_p); 102 JERRY_CONTEXT (ecma_gc_mark_recursion_limit)++; 103 } 104 else 105 { 106 /* Set the reference count of the non-marked gray object to 1 */ 107 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & ((ECMA_OBJECT_REF_ONE << 1) - 1)); 108 JERRY_ASSERT (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE); 109 } 110#else /* (JERRY_GC_MARK_LIMIT == 0) */ 111 /* Set the reference count of gray object to 0 */ 112 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1)); 113#endif /* (JERRY_GC_MARK_LIMIT != 0) */ 114 } 115} /* ecma_gc_set_object_visited */ 116 117/** 118 * Initialize GC information for the object 119 */ 120inline void 121ecma_init_gc_info (ecma_object_t *object_p) /**< object */ 122{ 123 JERRY_CONTEXT (ecma_gc_objects_number)++; 124 JERRY_CONTEXT (ecma_gc_new_objects)++; 125 126 JERRY_ASSERT (object_p->type_flags_refs < ECMA_OBJECT_REF_ONE); 127 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_REF_ONE); 128 129 object_p->gc_next_cp = JERRY_CONTEXT (ecma_gc_objects_cp); 130 ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_gc_objects_cp), object_p); 131#if defined(JERRY_REF_TRACKER) 132 ReportObjRefManip(object_p, kRefInit); 133#endif 134} /* ecma_init_gc_info */ 135 136/** 137 * Increase reference counter of an object 138 */ 139void 140ecma_ref_object (ecma_object_t *object_p) /**< object */ 141{ 142 if (JERRY_LIKELY (object_p->type_flags_refs < ECMA_OBJECT_MAX_REF)) 143 { 144 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs + ECMA_OBJECT_REF_ONE); 145 } 146 else 147 { 148 jerry_fatal (ERR_REF_COUNT_LIMIT); 149 } 150#if defined(JERRY_REF_TRACKER) 151 ReportObjRefManip(object_p, kRefRef); 152#endif 153} /* ecma_ref_object */ 154 155/** 156 * Decrease reference counter as a routine of GC reset marks phase. 157 */ 158inline void JERRY_ATTR_ALWAYS_INLINE 159ecma_unmark_deref_object (ecma_object_t *object_p) /**< object */ 160{ 161 JERRY_ASSERT (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE); 162 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs - ECMA_OBJECT_REF_ONE); 163#if defined(JERRY_REF_TRACKER) 164 ReportObjRefManip(object_p, kRefUnmark); 165#endif 166} /* ecma_unmark_deref_object */ 167 168/** 169 * Decrease reference counter of an object 170 */ 171inline void JERRY_ATTR_ALWAYS_INLINE 172ecma_deref_object (ecma_object_t *object_p) /**< object */ 173{ 174 JERRY_ASSERT (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE); 175 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs - ECMA_OBJECT_REF_ONE); 176#if defined(JERRY_REF_TRACKER) 177 ReportObjRefManip(object_p, kRefDeref); 178#endif 179} /* ecma_deref_object */ 180 181/** 182 * Mark referenced object from property 183 */ 184static inline void JERRY_ATTR_ALWAYS_INLINE 185ecma_gc_mark_properties (ecma_property_pair_t *property_pair_p) /**< property pair */ 186{ 187 for (uint32_t index = 0; index < ECMA_PROPERTY_PAIR_ITEM_COUNT; index++) 188 { 189 uint8_t property = property_pair_p->header.types[index]; 190 191 switch (ECMA_PROPERTY_GET_TYPE (property)) 192 { 193 case ECMA_PROPERTY_TYPE_NAMEDDATA: 194 { 195 ecma_value_t value = property_pair_p->values[index].value; 196 197 if (ecma_is_value_object (value)) 198 { 199 ecma_object_t *value_obj_p = ecma_get_object_from_value (value); 200 201 ecma_gc_set_object_visited (value_obj_p); 202 } 203 break; 204 } 205 case ECMA_PROPERTY_TYPE_NAMEDACCESSOR: 206 { 207 ecma_property_value_t *accessor_objs_p = property_pair_p->values + index; 208 209 ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (accessor_objs_p); 210 211 if (get_set_pair_p->getter_cp != JMEM_CP_NULL) 212 { 213 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp)); 214 } 215 216 if (get_set_pair_p->setter_cp != JMEM_CP_NULL) 217 { 218 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->setter_cp)); 219 } 220 break; 221 } 222 case ECMA_PROPERTY_TYPE_INTERNAL: 223 { 224 JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_DIRECT_STRING_MAGIC 225 && property_pair_p->names_cp[index] >= LIT_FIRST_INTERNAL_MAGIC_STRING); 226 break; 227 } 228 default: 229 { 230 JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_SPECIAL); 231 232 JERRY_ASSERT (property == ECMA_PROPERTY_TYPE_HASHMAP 233 || property == ECMA_PROPERTY_TYPE_DELETED); 234 break; 235 } 236 } 237 } 238} /* ecma_gc_mark_properties */ 239 240/** 241 * Mark objects referenced by bound function object. 242 */ 243static void JERRY_ATTR_NOINLINE 244ecma_gc_mark_bound_function_object (ecma_object_t *object_p) /**< bound function object */ 245{ 246 JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); 247 248 ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) object_p; 249 250 ecma_object_t *target_func_p; 251 target_func_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, 252 bound_func_p->header.u.bound_function.target_function); 253 254 ecma_gc_set_object_visited (target_func_p); 255 256 ecma_value_t args_len_or_this = bound_func_p->header.u.bound_function.args_len_or_this; 257 258 if (!ecma_is_value_integer_number (args_len_or_this)) 259 { 260 if (ecma_is_value_object (args_len_or_this)) 261 { 262 ecma_gc_set_object_visited (ecma_get_object_from_value (args_len_or_this)); 263 } 264 265 return; 266 } 267 268 ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this); 269 ecma_value_t *args_p = (ecma_value_t *) (bound_func_p + 1); 270 271 JERRY_ASSERT (args_length > 0); 272 273 for (ecma_integer_value_t i = 0; i < args_length; i++) 274 { 275 if (ecma_is_value_object (args_p[i])) 276 { 277 ecma_gc_set_object_visited (ecma_get_object_from_value (args_p[i])); 278 } 279 } 280} /* ecma_gc_mark_bound_function_object */ 281 282#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) 283/** 284 * Mark objects referenced by Promise built-in. 285 */ 286static void 287ecma_gc_mark_promise_object (ecma_extended_object_t *ext_object_p) /**< extended object */ 288{ 289 /* Mark promise result. */ 290 ecma_value_t result = ext_object_p->u.class_prop.u.value; 291 292 if (ecma_is_value_object (result)) 293 { 294 ecma_gc_set_object_visited (ecma_get_object_from_value (result)); 295 } 296 297 /* Mark all reactions. */ 298 ecma_promise_object_t *promise_object_p = (ecma_promise_object_t *) ext_object_p; 299 ecma_collection_t *collection_p = promise_object_p->reactions; 300 301 if (collection_p != NULL) 302 { 303 ecma_value_t *buffer_p = collection_p->buffer_p; 304 ecma_value_t *buffer_end_p = buffer_p + collection_p->item_count; 305 306 while (buffer_p < buffer_end_p) 307 { 308 ecma_value_t value = *buffer_p++; 309 310 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, value)); 311 312 if (JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (value)) 313 { 314 ecma_gc_set_object_visited (ecma_get_object_from_value (*buffer_p++)); 315 } 316 317 if (JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (value)) 318 { 319 ecma_gc_set_object_visited (ecma_get_object_from_value (*buffer_p++)); 320 } 321 } 322 } 323} /* ecma_gc_mark_promise_object */ 324 325#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ 326 327#if ENABLED (JERRY_ES2015_BUILTIN_MAP) 328/** 329 * Mark objects referenced by Map built-in. 330 */ 331static void 332ecma_gc_mark_map_object (ecma_object_t *object_p) /**< object */ 333{ 334 JERRY_ASSERT (object_p != NULL); 335 336 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; 337 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 338 map_object_p->u.class_prop.u.value); 339 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); 340 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); 341 342 for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_PAIR_SIZE) 343 { 344 ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i); 345 346 if (ecma_is_value_empty (entry_p->key)) 347 { 348 continue; 349 } 350 351 if (ecma_is_value_object (entry_p->key)) 352 { 353 ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->key)); 354 } 355 356 if (ecma_is_value_object (entry_p->value)) 357 { 358 ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->value)); 359 } 360 } 361} /* ecma_gc_mark_map_object */ 362#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ 363 364#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) 365/** 366 * Mark objects referenced by WeakMap built-in. 367 */ 368static void 369ecma_gc_mark_weakmap_object (ecma_object_t *object_p) /**< object */ 370{ 371 JERRY_ASSERT (object_p != NULL); 372 373 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; 374 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 375 map_object_p->u.class_prop.u.value); 376 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); 377 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); 378 379 for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_PAIR_SIZE) 380 { 381 ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i); 382 383 if (ecma_is_value_empty (entry_p->key)) 384 { 385 continue; 386 } 387 388 if (ecma_is_value_object (entry_p->value)) 389 { 390 ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->value)); 391 } 392 } 393} /* ecma_gc_mark_weakmap_object */ 394#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ 395 396#if ENABLED (JERRY_ES2015_BUILTIN_SET) 397/** 398 * Mark objects referenced by Set built-in. 399 */ 400static void 401ecma_gc_mark_set_object (ecma_object_t *object_p) /**< object */ 402{ 403 JERRY_ASSERT (object_p != NULL); 404 405 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; 406 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 407 map_object_p->u.class_prop.u.value); 408 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); 409 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); 410 411 for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_VALUE_SIZE) 412 { 413 ecma_value_t *entry_p = start_p + i; 414 415 if (ecma_is_value_empty (*entry_p)) 416 { 417 continue; 418 } 419 420 if (ecma_is_value_object (*entry_p)) 421 { 422 ecma_gc_set_object_visited (ecma_get_object_from_value (*entry_p)); 423 } 424 } 425} /* ecma_gc_mark_set_object */ 426#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ 427 428#if ENABLED (JERRY_ES2015) 429/** 430 * Mark objects referenced by inactive generator functions, async functions, etc. 431 */ 432static void 433ecma_gc_mark_executable_object (ecma_object_t *object_p) /**< object */ 434{ 435 vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p; 436 437 if (!ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED (executable_object_p->extended_object.u.class_prop.extra_info)) 438 { 439 /* All objects referenced by running executable objects are strong roots, 440 * and a finished executable object cannot refer to other values. */ 441 return; 442 } 443 444 if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_GENERATOR_ITERATE_AND_YIELD) 445 { 446 ecma_value_t iterator = executable_object_p->extended_object.u.class_prop.u.value; 447 ecma_gc_set_object_visited (ecma_get_object_from_value (iterator)); 448 } 449 450 ecma_gc_set_object_visited (executable_object_p->frame_ctx.lex_env_p); 451 452 if (ecma_is_value_object (executable_object_p->frame_ctx.this_binding)) 453 { 454 ecma_gc_set_object_visited (ecma_get_object_from_value (executable_object_p->frame_ctx.this_binding)); 455 } 456 457 const ecma_compiled_code_t *bytecode_header_p = executable_object_p->frame_ctx.bytecode_header_p; 458 size_t register_end; 459 460 if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) 461 { 462 cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; 463 register_end = args_p->register_end; 464 } 465 else 466 { 467 cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p; 468 register_end = args_p->register_end; 469 } 470 471 ecma_value_t *register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx); 472 ecma_value_t *register_end_p = register_p + register_end; 473 474 while (register_p < register_end_p) 475 { 476 if (ecma_is_value_object (*register_p)) 477 { 478 ecma_gc_set_object_visited (ecma_get_object_from_value (*register_p)); 479 } 480 481 register_p++; 482 } 483 484 register_p += executable_object_p->frame_ctx.context_depth; 485 register_end_p = executable_object_p->frame_ctx.stack_top_p; 486 487 while (register_p < register_end_p) 488 { 489 if (ecma_is_value_object (*register_p)) 490 { 491 ecma_gc_set_object_visited (ecma_get_object_from_value (*register_p)); 492 } 493 494 register_p++; 495 } 496} /* ecma_gc_mark_executable_object */ 497 498#endif /* ENABLED (JERRY_ES2015) */ 499 500#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) 501/** 502 * Mark the objects referenced by a proxy object 503 */ 504static void 505ecma_gc_mark_proxy_object (ecma_object_t *object_p) /**< proxy object */ 506{ 507 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (object_p)); 508 509 ecma_proxy_object_t *proxy_p = (ecma_proxy_object_t *) object_p; 510 511 if (!ecma_is_value_null (proxy_p->target)) 512 { 513 ecma_gc_set_object_visited (ecma_get_object_from_value (proxy_p->target)); 514 } 515 516 if (!ecma_is_value_null (proxy_p->handler)) 517 { 518 ecma_gc_set_object_visited (ecma_get_object_from_value (proxy_p->handler)); 519 } 520} /* ecma_gc_mark_proxy_object */ 521#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ 522 523/** 524 * Mark objects as visited starting from specified object as root 525 */ 526static void 527ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ 528{ 529 JERRY_ASSERT (object_p != NULL); 530 JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); 531 532 if (ecma_is_lexical_environment (object_p)) 533 { 534 jmem_cpointer_t outer_lex_env_cp = object_p->u2.outer_reference_cp; 535 536 if (outer_lex_env_cp != JMEM_CP_NULL) 537 { 538 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, outer_lex_env_cp)); 539 } 540 541 if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) 542 { 543 ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); 544 ecma_gc_set_object_visited (binding_object_p); 545 546 return; 547 } 548 } 549 else 550 { 551 jmem_cpointer_t proto_cp = object_p->u2.prototype_cp; 552 553 if (proto_cp != JMEM_CP_NULL) 554 { 555 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp)); 556 } 557 558 switch (ecma_get_object_type (object_p)) 559 { 560 case ECMA_OBJECT_TYPE_CLASS: 561 { 562 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 563 564 switch (ext_object_p->u.class_prop.class_id) 565 { 566#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) 567 case LIT_MAGIC_STRING_PROMISE_UL: 568 { 569 ecma_gc_mark_promise_object (ext_object_p); 570 break; 571 } 572#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ 573#if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) 574 case LIT_MAGIC_STRING_DATAVIEW_UL: 575 { 576 ecma_dataview_object_t *dataview_p = (ecma_dataview_object_t *) object_p; 577 ecma_gc_set_object_visited (dataview_p->buffer_p); 578 break; 579 } 580#endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */ 581#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) 582#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) 583 case LIT_MAGIC_STRING_WEAKSET_UL: 584 { 585 break; 586 } 587#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ 588#if ENABLED (JERRY_ES2015_BUILTIN_SET) 589 case LIT_MAGIC_STRING_SET_UL: 590 { 591 ecma_gc_mark_set_object (object_p); 592 break; 593 } 594#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ 595#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) 596 case LIT_MAGIC_STRING_WEAKMAP_UL: 597 { 598 ecma_gc_mark_weakmap_object (object_p); 599 break; 600 } 601#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ 602#if ENABLED (JERRY_ES2015_BUILTIN_MAP) 603 case LIT_MAGIC_STRING_MAP_UL: 604 { 605 ecma_gc_mark_map_object (object_p); 606 break; 607 } 608#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ 609#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ 610#if ENABLED (JERRY_ES2015) 611 case LIT_MAGIC_STRING_GENERATOR_UL: 612 { 613 ecma_gc_mark_executable_object (object_p); 614 break; 615 } 616#endif /* ENABLED (JERRY_ES2015) */ 617 default: 618 { 619 break; 620 } 621 } 622 623 break; 624 } 625 case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: 626 { 627 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 628 629 switch (ext_object_p->u.pseudo_array.type) 630 { 631#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) 632 case ECMA_PSEUDO_ARRAY_TYPEDARRAY: 633 case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO: 634 { 635 ecma_gc_set_object_visited (ecma_typedarray_get_arraybuffer (object_p)); 636 break; 637 } 638#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ 639#if ENABLED (JERRY_ES2015) 640 case ECMA_PSEUDO_ARRAY_ITERATOR: 641 case ECMA_PSEUDO_SET_ITERATOR: 642 case ECMA_PSEUDO_MAP_ITERATOR: 643 { 644 ecma_value_t iterated_value = ext_object_p->u.pseudo_array.u2.iterated_value; 645 if (!ecma_is_value_empty (iterated_value)) 646 { 647 ecma_gc_set_object_visited (ecma_get_object_from_value (iterated_value)); 648 } 649 break; 650 } 651 case ECMA_PSEUDO_STRING_ITERATOR: 652 { 653 break; 654 } 655#endif /* ENABLED (JERRY_ES2015) */ 656 default: 657 { 658 JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS); 659 660 ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, 661 ext_object_p->u.pseudo_array.u2.lex_env_cp); 662 663 ecma_gc_set_object_visited (lex_env_p); 664 break; 665 } 666 } 667 668 break; 669 } 670 case ECMA_OBJECT_TYPE_ARRAY: 671 { 672 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 673 674 if (ecma_op_array_is_fast_array (ext_object_p)) 675 { 676 if (object_p->u1.property_list_cp != JMEM_CP_NULL) 677 { 678 ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); 679 680 for (uint32_t i = 0; i < ext_object_p->u.array.length; i++) 681 { 682 if (ecma_is_value_object (values_p[i])) 683 { 684 ecma_gc_set_object_visited (ecma_get_object_from_value (values_p[i])); 685 } 686 } 687 } 688 689 return; 690 } 691 break; 692 } 693#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) 694 case ECMA_OBJECT_TYPE_PROXY: 695 { 696 ecma_gc_mark_proxy_object (object_p); 697 break; 698 } 699#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ 700 case ECMA_OBJECT_TYPE_BOUND_FUNCTION: 701 { 702 ecma_gc_mark_bound_function_object (object_p); 703 break; 704 } 705 case ECMA_OBJECT_TYPE_FUNCTION: 706 { 707 if (!ecma_get_object_is_builtin (object_p)) 708 { 709 ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; 710 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, 711 ext_func_p->u.function.scope_cp)); 712 713#if ENABLED (JERRY_ES2015) 714 const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code (ext_func_p); 715 716 if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) 717 { 718 ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; 719 720 if (ecma_is_value_object (arrow_func_p->this_binding)) 721 { 722 ecma_gc_set_object_visited (ecma_get_object_from_value (arrow_func_p->this_binding)); 723 } 724 725 if (ecma_is_value_object (arrow_func_p->new_target)) 726 { 727 ecma_gc_set_object_visited (ecma_get_object_from_value (arrow_func_p->new_target)); 728 } 729 } 730#endif /* ENABLED (JERRY_ES2015) */ 731 } 732 break; 733 } 734#if ENABLED (JERRY_ES2015) 735 case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: 736 { 737 ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; 738 739 if (ext_func_p->u.external_handler_cb == ecma_proxy_revoke_cb) 740 { 741 ecma_revocable_proxy_object_t *rev_proxy_p = (ecma_revocable_proxy_object_t *) object_p; 742 743 if (!ecma_is_value_null (rev_proxy_p->proxy)) 744 { 745 ecma_gc_set_object_visited (ecma_get_object_from_value (rev_proxy_p->proxy)); 746 } 747 } 748 break; 749 } 750#endif /* ENABLED (JERRY_ES2015) */ 751 default: 752 { 753 break; 754 } 755 } 756 } 757 758 jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp; 759 760#if ENABLED (JERRY_PROPRETY_HASHMAP) 761 if (prop_iter_cp != JMEM_CP_NULL) 762 { 763 ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); 764 if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) 765 { 766 prop_iter_cp = prop_iter_p->next_property_cp; 767 } 768 } 769#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ 770 771 while (prop_iter_cp != JMEM_CP_NULL) 772 { 773 ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); 774 JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); 775 776 ecma_gc_mark_properties ((ecma_property_pair_t *) prop_iter_p); 777 778 prop_iter_cp = prop_iter_p->next_property_cp; 779 } 780} /* ecma_gc_mark */ 781 782/** 783 * Free the native handle/pointer by calling its free callback. 784 */ 785static void 786ecma_gc_free_native_pointer (ecma_property_t *property_p) /**< property */ 787{ 788 JERRY_ASSERT (property_p != NULL); 789 790 ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p); 791 ecma_native_pointer_t *native_pointer_p; 792 793 native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, 794 value_p->value); 795 796 while (native_pointer_p != NULL) 797 { 798 if (native_pointer_p->info_p != NULL) 799 { 800 ecma_object_native_free_callback_t free_cb = native_pointer_p->info_p->free_cb; 801 802 if (free_cb != NULL) 803 { 804 free_cb (native_pointer_p->data_p); 805 } 806 } 807 808 ecma_native_pointer_t *next_p = native_pointer_p->next_p; 809 810 jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t)); 811 812 native_pointer_p = next_p; 813 } 814} /* ecma_gc_free_native_pointer */ 815 816/** 817 * Free specified fast access mode array object. 818 */ 819static void 820ecma_free_fast_access_array (ecma_object_t *object_p) /**< fast access mode array object to free */ 821{ 822 JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); 823 824 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 825 const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (ext_object_p->u.array.length); 826 827 if (object_p->u1.property_list_cp != JMEM_CP_NULL) 828 { 829 ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); 830 831 for (uint32_t i = 0; i < aligned_length; i++) 832 { 833 ecma_free_value_if_not_object (values_p[i]); 834 } 835 836 jmem_heap_free_block (values_p, aligned_length * sizeof (ecma_value_t)); 837 } 838 839 ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); 840} /* ecma_free_fast_access_array */ 841 842#if ENABLED (JERRY_ES2015) 843 844/** 845 * Free non-objects referenced by inactive generator functions, async functions, etc. 846 * 847 * @return total object size 848 */ 849static size_t 850ecma_gc_free_executable_object (ecma_object_t *object_p) /**< object */ 851{ 852 vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p; 853 854 const ecma_compiled_code_t *bytecode_header_p = executable_object_p->frame_ctx.bytecode_header_p; 855 size_t size, register_end; 856 857 if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) 858 { 859 cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; 860 861 register_end = args_p->register_end; 862 size = (register_end + (size_t) args_p->stack_limit) * sizeof (ecma_value_t); 863 } 864 else 865 { 866 cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p; 867 868 register_end = args_p->register_end; 869 size = (register_end + (size_t) args_p->stack_limit) * sizeof (ecma_value_t); 870 } 871 872 size = JERRY_ALIGNUP (sizeof (vm_executable_object_t) + size, sizeof (uintptr_t)); 873 874 JERRY_ASSERT (!(executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_RUNNING)); 875 876 ecma_bytecode_deref ((ecma_compiled_code_t *) bytecode_header_p); 877 878 if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_COMPLETED) 879 { 880 return size; 881 } 882 883 ecma_free_value_if_not_object (executable_object_p->frame_ctx.this_binding); 884 885 ecma_value_t *register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx); 886 ecma_value_t *register_end_p = register_p + register_end; 887 888 while (register_p < register_end_p) 889 { 890 ecma_free_value_if_not_object (*register_p++); 891 } 892 893 if (executable_object_p->frame_ctx.context_depth > 0) 894 { 895 ecma_value_t *context_end_p = register_p; 896 897 register_p += executable_object_p->frame_ctx.context_depth; 898 899 ecma_value_t *context_top_p = register_p; 900 901 do 902 { 903 context_top_p[-1] &= (uint32_t) ~(VM_CONTEXT_HAS_LEX_ENV | VM_CONTEXT_CLOSE_ITERATOR); 904 905 uint32_t offsets = vm_get_context_value_offsets (context_top_p); 906 907 while (VM_CONTEXT_HAS_NEXT_OFFSET (offsets)) 908 { 909 int32_t offset = VM_CONTEXT_GET_NEXT_OFFSET (offsets); 910 911 if (ecma_is_value_object (context_top_p[offset])) 912 { 913 context_top_p[offset] = ECMA_VALUE_UNDEFINED; 914 } 915 916 offsets >>= VM_CONTEXT_OFFSET_SHIFT; 917 } 918 919 context_top_p = vm_stack_context_abort (&executable_object_p->frame_ctx, context_top_p); 920 } 921 while (context_top_p > context_end_p); 922 } 923 924 register_end_p = executable_object_p->frame_ctx.stack_top_p; 925 926 while (register_p < register_end_p) 927 { 928 ecma_free_value_if_not_object (*register_p++); 929 } 930 931 return size; 932} /* ecma_gc_free_executable_object */ 933 934#endif /* ENABLED (JERRY_ES2015) */ 935 936/** 937 * Free properties of an object 938 */ 939void 940ecma_gc_free_properties (ecma_object_t *object_p) /**< object */ 941{ 942 jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp; 943 944#if ENABLED (JERRY_PROPRETY_HASHMAP) 945 if (prop_iter_cp != JMEM_CP_NULL) 946 { 947 ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, 948 prop_iter_cp); 949 if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) 950 { 951 ecma_property_hashmap_free (object_p); 952 prop_iter_cp = object_p->u1.property_list_cp; 953 } 954 } 955#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ 956 957 while (prop_iter_cp != JMEM_CP_NULL) 958 { 959 ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); 960 JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); 961 962 /* Both cannot be deleted. */ 963 JERRY_ASSERT (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED 964 || prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED); 965 966 ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; 967 968 for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) 969 { 970 ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); 971 jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; 972 973 if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC) 974 { 975 /* Call the native's free callback. */ 976 if (JERRY_UNLIKELY (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER)) 977 { 978 ecma_gc_free_native_pointer (property_p); 979 } 980#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) 981 else if (JERRY_UNLIKELY (name_cp == LIT_INTERNAL_MAGIC_STRING_WEAK_REFS)) 982 { 983 ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 984 ECMA_PROPERTY_VALUE_PTR (property_p)->value); 985 for (uint32_t j = 0; j < refs_p->item_count; j++) 986 { 987 const ecma_value_t value = refs_p->buffer_p[j]; 988 if (!ecma_is_value_empty (value)) 989 { 990 ecma_object_t *container_p = ecma_get_object_from_value (value); 991 992 ecma_op_container_remove_weak_entry (container_p, 993 ecma_make_object_value (object_p)); 994 } 995 } 996 997 ecma_collection_destroy (refs_p); 998 } 999#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ 1000 } 1001 1002 if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED) 1003 { 1004 ecma_free_property (object_p, name_cp, property_p); 1005 } 1006 } 1007 1008 prop_iter_cp = prop_iter_p->next_property_cp; 1009 1010 ecma_dealloc_property_pair (prop_pair_p); 1011 } 1012} /* ecma_gc_free_properties */ 1013 1014/** 1015 * Free specified object. 1016 */ 1017static void 1018ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ 1019{ 1020 JERRY_ASSERT (object_p != NULL 1021 && !ecma_gc_is_object_visited (object_p) 1022 && ((object_p->type_flags_refs & ECMA_OBJECT_REF_MASK) == ECMA_OBJECT_NON_VISITED)); 1023 1024 JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_number) > 0); 1025 JERRY_CONTEXT (ecma_gc_objects_number)--; 1026 1027 if (ecma_is_lexical_environment (object_p)) 1028 { 1029 if (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) 1030 { 1031 ecma_gc_free_properties (object_p); 1032 } 1033 1034 ecma_dealloc_object (object_p); 1035 return; 1036 } 1037 1038 ecma_object_type_t object_type = ecma_get_object_type (object_p); 1039 1040 size_t ext_object_size = sizeof (ecma_extended_object_t); 1041 1042 if (JERRY_UNLIKELY (ecma_get_object_is_builtin (object_p))) 1043 { 1044 uint8_t length_and_bitset_size; 1045 1046 if (object_type == ECMA_OBJECT_TYPE_CLASS 1047 || object_type == ECMA_OBJECT_TYPE_ARRAY) 1048 { 1049 ext_object_size = sizeof (ecma_extended_built_in_object_t); 1050 length_and_bitset_size = ((ecma_extended_built_in_object_t *) object_p)->built_in.length_and_bitset_size; 1051 ext_object_size += (2 * sizeof (uint32_t)) * (length_and_bitset_size >> ECMA_BUILT_IN_BITSET_SHIFT); 1052 } 1053 else 1054 { 1055 length_and_bitset_size = ((ecma_extended_object_t *) object_p)->u.built_in.length_and_bitset_size; 1056 ext_object_size += (2 * sizeof (uint32_t)) * (length_and_bitset_size >> ECMA_BUILT_IN_BITSET_SHIFT); 1057 1058 ecma_gc_free_properties (object_p); 1059 ecma_dealloc_extended_object (object_p, ext_object_size); 1060 return; 1061 } 1062 } 1063 1064 switch (object_type) 1065 { 1066 case ECMA_OBJECT_TYPE_GENERAL: 1067 { 1068 ecma_gc_free_properties (object_p); 1069 ecma_dealloc_object (object_p); 1070 return; 1071 } 1072 case ECMA_OBJECT_TYPE_ARRAY: 1073 { 1074 if (ecma_op_array_is_fast_array ((ecma_extended_object_t *) object_p)) 1075 { 1076 ecma_free_fast_access_array (object_p); 1077 return; 1078 } 1079 break; 1080 } 1081 case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: 1082 { 1083#if ENABLED (JERRY_ES2015) 1084 ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; 1085 1086 if (ext_func_p->u.external_handler_cb == ecma_proxy_revoke_cb) 1087 { 1088 ext_object_size = sizeof (ecma_revocable_proxy_object_t); 1089 } 1090#endif /* ENABLED (JERRY_ES2015) */ 1091 break; 1092 } 1093 case ECMA_OBJECT_TYPE_CLASS: 1094 { 1095 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 1096 1097 switch (ext_object_p->u.class_prop.class_id) 1098 { 1099#if ENABLED (JERRY_ES2015) 1100 case LIT_MAGIC_STRING_SYMBOL_UL: 1101#endif /* ENABLED (JERRY_ES2015) */ 1102 case LIT_MAGIC_STRING_STRING_UL: 1103 case LIT_MAGIC_STRING_NUMBER_UL: 1104 { 1105 ecma_free_value (ext_object_p->u.class_prop.u.value); 1106 break; 1107 } 1108 1109 case LIT_MAGIC_STRING_DATE_UL: 1110 { 1111 ecma_number_t *num_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, 1112 ext_object_p->u.class_prop.u.value); 1113 ecma_dealloc_number (num_p); 1114 break; 1115 } 1116 case LIT_MAGIC_STRING_REGEXP_UL: 1117 { 1118 ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_compiled_code_t, 1119 ext_object_p->u.class_prop.u.value); 1120 1121 ecma_bytecode_deref (bytecode_p); 1122 1123 break; 1124 } 1125#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) 1126 case LIT_MAGIC_STRING_ARRAY_BUFFER_UL: 1127 { 1128 ecma_length_t arraybuffer_length = ext_object_p->u.class_prop.u.length; 1129 1130 if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) 1131 { 1132 ext_object_size = sizeof (ecma_arraybuffer_external_info); 1133 1134 /* Call external free callback if any. */ 1135 ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; 1136 JERRY_ASSERT (array_p != NULL); 1137 1138 if (array_p->free_cb != NULL) 1139 { 1140 (array_p->free_cb) (array_p->buffer_p); 1141 } 1142 } 1143 else 1144 { 1145 ext_object_size += arraybuffer_length; 1146 } 1147 1148 break; 1149 } 1150#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ 1151#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) 1152 case LIT_MAGIC_STRING_PROMISE_UL: 1153 { 1154 ecma_free_value_if_not_object (ext_object_p->u.class_prop.u.value); 1155 1156 /* Reactions only contains objects. */ 1157 ecma_collection_destroy (((ecma_promise_object_t *) object_p)->reactions); 1158 1159 ext_object_size = sizeof (ecma_promise_object_t); 1160 break; 1161 } 1162#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ 1163#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) 1164#if ENABLED (JERRY_ES2015_BUILTIN_MAP) 1165 case LIT_MAGIC_STRING_MAP_UL: 1166#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ 1167#if ENABLED (JERRY_ES2015_BUILTIN_SET) 1168 case LIT_MAGIC_STRING_SET_UL: 1169#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ 1170#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) 1171 case LIT_MAGIC_STRING_WEAKMAP_UL: 1172#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ 1173#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) 1174 case LIT_MAGIC_STRING_WEAKSET_UL: 1175#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ 1176 { 1177 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; 1178 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, 1179 map_object_p->u.class_prop.u.value); 1180 ecma_op_container_free_entries (object_p); 1181 ecma_collection_destroy (container_p); 1182 1183 break; 1184 } 1185#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ 1186#if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) 1187 case LIT_MAGIC_STRING_DATAVIEW_UL: 1188 { 1189 ext_object_size = sizeof (ecma_dataview_object_t); 1190 break; 1191 } 1192#endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */ 1193#if ENABLED (JERRY_ES2015) 1194 case LIT_MAGIC_STRING_GENERATOR_UL: 1195 { 1196 ext_object_size = ecma_gc_free_executable_object (object_p); 1197 break; 1198 } 1199#endif /* ENABLED (JERRY_ES2015) */ 1200 default: 1201 { 1202 /* The undefined id represents an uninitialized class. */ 1203 JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_UNDEFINED 1204 || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_ARGUMENTS_UL 1205 || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL 1206 || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_ERROR_UL 1207 || ext_object_p->u.class_prop.class_id == LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT); 1208 break; 1209 } 1210 } 1211 1212 break; 1213 } 1214#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) 1215 case ECMA_OBJECT_TYPE_PROXY: 1216 { 1217 ext_object_size = sizeof (ecma_proxy_object_t); 1218 break; 1219 } 1220#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ 1221 case ECMA_OBJECT_TYPE_FUNCTION: 1222 { 1223 /* Function with byte-code (not a built-in function). */ 1224 ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; 1225 1226#if ENABLED (JERRY_SNAPSHOT_EXEC) 1227 if (ext_func_p->u.function.bytecode_cp != ECMA_NULL_POINTER) 1228 { 1229#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ 1230 ecma_compiled_code_t *byte_code_p = (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, 1231 ext_func_p->u.function.bytecode_cp)); 1232 1233#if ENABLED (JERRY_ES2015) 1234 if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) 1235 { 1236 ecma_free_value_if_not_object (((ecma_arrow_function_t *) object_p)->this_binding); 1237 ecma_free_value_if_not_object (((ecma_arrow_function_t *) object_p)->new_target); 1238 ext_object_size = sizeof (ecma_arrow_function_t); 1239 } 1240#endif /* ENABLED (JERRY_ES2015) */ 1241 1242 ecma_bytecode_deref (byte_code_p); 1243#if ENABLED (JERRY_SNAPSHOT_EXEC) 1244 } 1245 else 1246 { 1247 ext_object_size = sizeof (ecma_static_function_t); 1248 } 1249#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ 1250 break; 1251 } 1252 case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: 1253 { 1254 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 1255 1256 switch (ext_object_p->u.pseudo_array.type) 1257 { 1258 case ECMA_PSEUDO_ARRAY_ARGUMENTS: 1259 { 1260 JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS); 1261 1262 ecma_length_t formal_params_number = ext_object_p->u.pseudo_array.u1.length; 1263 ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1); 1264 1265 for (ecma_length_t i = 0; i < formal_params_number; i++) 1266 { 1267 if (arg_Literal_p[i] != ECMA_VALUE_EMPTY) 1268 { 1269 ecma_string_t *name_p = ecma_get_string_from_value (arg_Literal_p[i]); 1270 ecma_deref_ecma_string (name_p); 1271 } 1272 } 1273 1274 size_t formal_params_size = formal_params_number * sizeof (ecma_value_t); 1275 ext_object_size += formal_params_size; 1276 break; 1277 } 1278#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) 1279 case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO: 1280 { 1281 ext_object_size = sizeof (ecma_extended_typedarray_object_t); 1282 break; 1283 } 1284#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ 1285#if ENABLED (JERRY_ES2015) 1286 case ECMA_PSEUDO_STRING_ITERATOR: 1287 { 1288 ecma_value_t iterated_value = ext_object_p->u.pseudo_array.u2.iterated_value; 1289 1290 if (!ecma_is_value_empty (iterated_value)) 1291 { 1292 ecma_deref_ecma_string (ecma_get_string_from_value (iterated_value)); 1293 } 1294 1295 break; 1296 } 1297#endif /* ENABLED (JERRY_ES2015) */ 1298 default: 1299 { 1300 JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY 1301 || ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ITERATOR 1302 || ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_SET_ITERATOR 1303 || ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_MAP_ITERATOR); 1304 break; 1305 } 1306 } 1307 1308 break; 1309 } 1310 case ECMA_OBJECT_TYPE_BOUND_FUNCTION: 1311 { 1312 ext_object_size = sizeof (ecma_bound_function_t); 1313 ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) object_p; 1314 1315 ecma_value_t args_len_or_this = bound_func_p->header.u.bound_function.args_len_or_this; 1316 1317 if (!ecma_is_value_integer_number (args_len_or_this)) 1318 { 1319 ecma_free_value_if_not_object (args_len_or_this); 1320 break; 1321 } 1322 1323 ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this); 1324 ecma_value_t *args_p = (ecma_value_t *) (bound_func_p + 1); 1325 1326 for (ecma_integer_value_t i = 0; i < args_length; i++) 1327 { 1328 ecma_free_value_if_not_object (args_p[i]); 1329 } 1330 1331 size_t args_size = ((size_t) args_length) * sizeof (ecma_value_t); 1332 ext_object_size += args_size; 1333 break; 1334 } 1335 default: 1336 { 1337 JERRY_UNREACHABLE (); 1338 } 1339 } 1340 1341 ecma_gc_free_properties (object_p); 1342 ecma_dealloc_extended_object (object_p, ext_object_size); 1343} /* ecma_gc_free_object */ 1344 1345bool g_isGCEnabled = true; 1346void EnableGC() 1347{ 1348 g_isGCEnabled = true; 1349 ecma_gc_run(); 1350} 1351 1352void DisableGC() 1353{ 1354 g_isGCEnabled = false; 1355} 1356 1357/** 1358 * Run garbage collection, freeing objects that are no longer referenced. 1359 */ 1360void 1361ecma_gc_run (void) 1362{ 1363#if (JERRY_GC_MARK_LIMIT != 0) 1364 JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) == JERRY_GC_MARK_LIMIT); 1365#endif /* (JERRY_GC_MARK_LIMIT != 0) */ 1366 1367 JERRY_CONTEXT (ecma_gc_new_objects) = 0; 1368 1369 if (!g_isGCEnabled) { 1370 return; 1371 } 1372 1373 ecma_object_t black_list_head; 1374 black_list_head.gc_next_cp = JMEM_CP_NULL; 1375 ecma_object_t *black_end_p = &black_list_head; 1376 1377 ecma_object_t white_gray_list_head; 1378 white_gray_list_head.gc_next_cp = JERRY_CONTEXT (ecma_gc_objects_cp); 1379 1380 ecma_object_t *obj_prev_p = &white_gray_list_head; 1381 jmem_cpointer_t obj_iter_cp = obj_prev_p->gc_next_cp; 1382 ecma_object_t *obj_iter_p; 1383 1384 /* Move root objects (i.e. they have global or stack references) to the black list. */ 1385 while (obj_iter_cp != JMEM_CP_NULL) 1386 { 1387 obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp); 1388 const jmem_cpointer_t obj_next_cp = obj_iter_p->gc_next_cp; 1389 1390 JERRY_ASSERT (obj_prev_p == NULL 1391 || ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_prev_p->gc_next_cp) == obj_iter_p); 1392 1393 if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE) 1394 { 1395 /* Moving the object to list of marked objects. */ 1396 obj_prev_p->gc_next_cp = obj_next_cp; 1397 1398 black_end_p->gc_next_cp = obj_iter_cp; 1399 black_end_p = obj_iter_p; 1400 } 1401 else 1402 { 1403 obj_iter_p->type_flags_refs |= ECMA_OBJECT_NON_VISITED; 1404 obj_prev_p = obj_iter_p; 1405 } 1406 1407 obj_iter_cp = obj_next_cp; 1408 } 1409 1410 black_end_p->gc_next_cp = JMEM_CP_NULL; 1411 1412 /* Mark root objects. */ 1413 obj_iter_cp = black_list_head.gc_next_cp; 1414 while (obj_iter_cp != JMEM_CP_NULL) 1415 { 1416 obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp); 1417 ecma_gc_mark (obj_iter_p); 1418#if defined(JERRY_HEAPDUMP) 1419 if (GetHeapdumpTracing()) { 1420 DumpInfoObject(obj_iter_p, HEAPDUMP_OBJECT_ROOT); 1421 } 1422#endif 1423 obj_iter_cp = obj_iter_p->gc_next_cp; 1424 } 1425 1426 /* Mark non-root objects. */ 1427 bool marked_anything_during_current_iteration; 1428 1429 do 1430 { 1431#if (JERRY_GC_MARK_LIMIT != 0) 1432 JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) == JERRY_GC_MARK_LIMIT); 1433#endif /* (JERRY_GC_MARK_LIMIT != 0) */ 1434 1435 marked_anything_during_current_iteration = false; 1436 1437 obj_prev_p = &white_gray_list_head; 1438 obj_iter_cp = obj_prev_p->gc_next_cp; 1439 1440 while (obj_iter_cp != JMEM_CP_NULL) 1441 { 1442 obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp); 1443 const jmem_cpointer_t obj_next_cp = obj_iter_p->gc_next_cp; 1444 1445 JERRY_ASSERT (obj_prev_p == NULL 1446 || ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_prev_p->gc_next_cp) == obj_iter_p); 1447 1448 if (ecma_gc_is_object_visited (obj_iter_p)) 1449 { 1450 /* Moving the object to list of marked objects */ 1451 obj_prev_p->gc_next_cp = obj_next_cp; 1452 1453 black_end_p->gc_next_cp = obj_iter_cp; 1454 black_end_p = obj_iter_p; 1455 1456#if (JERRY_GC_MARK_LIMIT != 0) 1457 if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE) 1458 { 1459 /* Set the reference count of non-marked gray object to 0 */ 1460 obj_iter_p->type_flags_refs = (uint16_t) (obj_iter_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1)); 1461 ecma_gc_mark (obj_iter_p); 1462#if defined(JERRY_HEAPDUMP) 1463 if (GetHeapdumpTracing()) { 1464 DumpInfoObject(obj_iter_p, HEAPDUMP_OBJECT_SIMPLE); 1465 } 1466#endif 1467 marked_anything_during_current_iteration = true; 1468 } 1469#else /* (JERRY_GC_MARK_LIMIT == 0) */ 1470 marked_anything_during_current_iteration = true; 1471#endif /* (JERRY_GC_MARK_LIMIT != 0) */ 1472 } 1473 else 1474 { 1475 obj_prev_p = obj_iter_p; 1476 } 1477 1478 obj_iter_cp = obj_next_cp; 1479 } 1480 } 1481 while (marked_anything_during_current_iteration); 1482 1483 black_end_p->gc_next_cp = JMEM_CP_NULL; 1484 JERRY_CONTEXT (ecma_gc_objects_cp) = black_list_head.gc_next_cp; 1485 1486 /* Sweep objects that are currently unmarked. */ 1487 obj_iter_cp = white_gray_list_head.gc_next_cp; 1488 1489 while (obj_iter_cp != JMEM_CP_NULL) 1490 { 1491 obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp); 1492 const jmem_cpointer_t obj_next_cp = obj_iter_p->gc_next_cp; 1493 1494 JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p)); 1495 1496 ecma_gc_free_object (obj_iter_p); 1497 obj_iter_cp = obj_next_cp; 1498 } 1499 1500#if ENABLED (JERRY_BUILTIN_REGEXP) 1501 /* Free RegExp bytecodes stored in cache */ 1502 re_cache_gc (); 1503#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ 1504} /* ecma_gc_run */ 1505 1506/** 1507 * Try to free some memory (depending on memory pressure). 1508 * 1509 * When called with JMEM_PRESSURE_FULL, the engine will be terminated with ERR_OUT_OF_MEMORY. 1510 */ 1511void 1512ecma_free_unused_memory (jmem_pressure_t pressure) /**< current pressure */ 1513{ 1514#if ENABLED (JERRY_DEBUGGER) 1515 while ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) 1516 /* This shall prevent receiving messaging during evaluation */ 1517 && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE) 1518 && JERRY_CONTEXT (debugger_byte_code_free_tail) != ECMA_NULL_POINTER) 1519 { 1520 /* Wait until all byte code is freed or the connection is aborted. */ 1521 jerry_debugger_receive (NULL); 1522 } 1523#endif /* ENABLED (JERRY_DEBUGGER) */ 1524 1525 if (JERRY_LIKELY (pressure == JMEM_PRESSURE_LOW)) 1526 { 1527#if ENABLED (JERRY_PROPRETY_HASHMAP) 1528 if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) > ECMA_PROP_HASHMAP_ALLOC_ON) 1529 { 1530 --JERRY_CONTEXT (ecma_prop_hashmap_alloc_state); 1531 } 1532 JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_HIGH_PRESSURE_GC; 1533#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ 1534 /* 1535 * If there is enough newly allocated objects since last GC, probably it is worthwhile to start GC now. 1536 * Otherwise, probability to free sufficient space is considered to be low. 1537 */ 1538 size_t new_objects_fraction = CONFIG_ECMA_GC_NEW_OBJECTS_FRACTION; 1539 1540 if (JERRY_CONTEXT (ecma_gc_new_objects) * new_objects_fraction > JERRY_CONTEXT (ecma_gc_objects_number)) 1541 { 1542 ecma_gc_run (); 1543 } 1544 1545 return; 1546 } 1547 else if (pressure == JMEM_PRESSURE_HIGH) 1548 { 1549 /* Freeing as much memory as we currently can */ 1550#if ENABLED (JERRY_PROPRETY_HASHMAP) 1551 if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_HIGH_PRESSURE_GC) 1552 { 1553 JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_MAX; 1554 } 1555 else if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) < ECMA_PROP_HASHMAP_ALLOC_MAX) 1556 { 1557 ++JERRY_CONTEXT (ecma_prop_hashmap_alloc_state); 1558 JERRY_CONTEXT (status_flags) |= ECMA_STATUS_HIGH_PRESSURE_GC; 1559 } 1560#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ 1561 1562 ecma_gc_run (); 1563 1564#if ENABLED (JERRY_PROPRETY_HASHMAP) 1565 /* Free hashmaps of remaining objects. */ 1566 jmem_cpointer_t obj_iter_cp = JERRY_CONTEXT (ecma_gc_objects_cp); 1567 1568 while (obj_iter_cp != JMEM_CP_NULL) 1569 { 1570 ecma_object_t *obj_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp); 1571 1572 if (!ecma_is_lexical_environment (obj_iter_p) 1573 || ecma_get_lex_env_type (obj_iter_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) 1574 { 1575 if (!ecma_is_lexical_environment (obj_iter_p) 1576 && ecma_op_object_is_fast_array (obj_iter_p)) 1577 { 1578 obj_iter_cp = obj_iter_p->gc_next_cp; 1579 continue; 1580 } 1581 1582 jmem_cpointer_t prop_iter_cp = obj_iter_p->u1.property_list_cp; 1583 1584 if (prop_iter_cp != JMEM_CP_NULL) 1585 { 1586 ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); 1587 1588 if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) 1589 { 1590 ecma_property_hashmap_free (obj_iter_p); 1591 } 1592 } 1593 1594 } 1595 1596 obj_iter_cp = obj_iter_p->gc_next_cp; 1597 } 1598#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ 1599 1600 jmem_pools_collect_empty (); 1601 return; 1602 } 1603 else if (JERRY_UNLIKELY (pressure == JMEM_PRESSURE_FULL)) 1604 { 1605 jerry_fatal (ERR_OUT_OF_MEMORY); 1606 } 1607 else 1608 { 1609 JERRY_ASSERT (pressure == JMEM_PRESSURE_NONE); 1610 JERRY_UNREACHABLE (); 1611 } 1612} /* ecma_free_unused_memory */ 1613 1614/** 1615 * @} 1616 * @} 1617 */ 1618