/** * Run garbage collection */ void ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */ { JERRY_CONTEXT (ecma_gc_new_objects) = 0; JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK] == NULL); /* if some object is referenced from stack or globals (i.e. it is root), mark it */ for (ecma_object_t *obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY]; obj_iter_p != NULL; obj_iter_p = ecma_gc_get_object_next (obj_iter_p)) { JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p)); if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE) { ecma_gc_set_object_visited (obj_iter_p, true); } } bool marked_anything_during_current_iteration = false; do { marked_anything_during_current_iteration = false; ecma_object_t *obj_prev_p = NULL; ecma_object_t *obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY]; while (obj_iter_p != NULL) { ecma_object_t *obj_next_p = ecma_gc_get_object_next (obj_iter_p); if (ecma_gc_is_object_visited (obj_iter_p)) { /* Moving the object to list of marked objects */ ecma_gc_set_object_next (obj_iter_p, JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK]); JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK] = obj_iter_p; if (likely (obj_prev_p != NULL)) { JERRY_ASSERT (ecma_gc_get_object_next (obj_prev_p) == obj_iter_p); ecma_gc_set_object_next (obj_prev_p, obj_next_p); } else { JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY] = obj_next_p; } ecma_gc_mark (obj_iter_p); marked_anything_during_current_iteration = true; } else { obj_prev_p = obj_iter_p; } obj_iter_p = obj_next_p; } } while (marked_anything_during_current_iteration); /* Sweeping objects that are currently unmarked */ ecma_object_t *obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY]; while (obj_iter_p != NULL) { ecma_object_t *obj_next_p = ecma_gc_get_object_next (obj_iter_p); JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p)); ecma_gc_sweep (obj_iter_p); obj_iter_p = obj_next_p; } if (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH) { /* Remove the property hashmap of BLACK objects */ obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK]; while (obj_iter_p != NULL) { JERRY_ASSERT (ecma_gc_is_object_visited (obj_iter_p)); if (!ecma_is_lexical_environment (obj_iter_p) || ecma_get_lex_env_type (obj_iter_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_iter_p); if (prop_iter_p != NULL && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_HASHMAP) { ecma_property_hashmap_free (obj_iter_p); } } obj_iter_p = ecma_gc_get_object_next (obj_iter_p); } } /* Unmarking all objects */ ecma_object_t *black_objects = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK]; JERRY_CONTEXT (ecma_gc_objects_lists)[ECMA_GC_COLOR_WHITE_GRAY] = black_objects; JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK] = NULL; JERRY_CONTEXT (ecma_gc_visited_flip_flag) = !JERRY_CONTEXT (ecma_gc_visited_flip_flag); #ifndef CONFIG_DISABLE_REGEXP_BUILTIN /* Free RegExp bytecodes stored in cache */ re_cache_gc_run (); #endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ } /* ecma_gc_run */
/** * Low level delete of array items from new_length to old_length * * Note: new_length must be less than old_length * * @return the updated value of new_length */ uint32_t ecma_delete_array_properties (ecma_object_t *object_p, /**< object */ uint32_t new_length, /**< new length */ uint32_t old_length) /**< old length */ { JERRY_ASSERT (new_length < old_length); /* First the minimum value of new_length is updated. */ ecma_property_header_t *current_prop_p = ecma_get_property_list (object_p); if (current_prop_p == NULL) { return new_length; } if (current_prop_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) { current_prop_p = ECMA_GET_POINTER (ecma_property_header_t, current_prop_p->next_property_cp); } while (current_prop_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (current_prop_p)); ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) current_prop_p; for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { if (ECMA_PROPERTY_IS_NAMED_PROPERTY (current_prop_p->types[i]) && !ecma_is_property_configurable (current_prop_p->types[i])) { uint32_t index = ecma_string_get_property_index (current_prop_p->types[i], prop_pair_p->names_cp[i]); if (index < old_length && index >= new_length) { JERRY_ASSERT (index != ECMA_STRING_NOT_ARRAY_INDEX); new_length = index + 1; if (new_length == old_length) { /* Early return. */ return new_length; } } } } current_prop_p = ECMA_GET_POINTER (ecma_property_header_t, current_prop_p->next_property_cp); } /* Second all properties between new_length and old_length are deleted. */ current_prop_p = ecma_get_property_list (object_p); ecma_property_header_t *prev_prop_p = NULL; ecma_property_hashmap_delete_status hashmap_status = ECMA_PROPERTY_HASHMAP_DELETE_NO_HASHMAP; if (current_prop_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) { prev_prop_p = current_prop_p; current_prop_p = ECMA_GET_POINTER (ecma_property_header_t, current_prop_p->next_property_cp); hashmap_status = ECMA_PROPERTY_HASHMAP_DELETE_HAS_HASHMAP; } while (current_prop_p != NULL) { ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) current_prop_p; for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { if (ECMA_PROPERTY_IS_NAMED_PROPERTY (current_prop_p->types[i]) && ecma_is_property_configurable (current_prop_p->types[i])) { uint32_t index = ecma_string_get_property_index (current_prop_p->types[i], prop_pair_p->names_cp[i]); if (index < old_length && index >= new_length) { JERRY_ASSERT (index != ECMA_STRING_NOT_ARRAY_INDEX); if (hashmap_status == ECMA_PROPERTY_HASHMAP_DELETE_HAS_HASHMAP) { hashmap_status = ecma_property_hashmap_delete (object_p, prop_pair_p->names_cp[i], current_prop_p->types + i); } ecma_free_property (object_p, prop_pair_p->names_cp[i], current_prop_p->types + i); JERRY_ASSERT (current_prop_p->types[i] == ECMA_PROPERTY_TYPE_DELETED); } } } if (current_prop_p->types[0] == ECMA_PROPERTY_TYPE_DELETED && current_prop_p->types[1] == ECMA_PROPERTY_TYPE_DELETED) { if (prev_prop_p == NULL) { object_p->property_list_or_bound_object_cp = current_prop_p->next_property_cp; } else { prev_prop_p->next_property_cp = current_prop_p->next_property_cp; } ecma_property_header_t *next_prop_p = ECMA_GET_POINTER (ecma_property_header_t, current_prop_p->next_property_cp); ecma_dealloc_property_pair ((ecma_property_pair_t *) current_prop_p); current_prop_p = next_prop_p; } else { prev_prop_p = current_prop_p; current_prop_p = ECMA_GET_POINTER (ecma_property_header_t, current_prop_p->next_property_cp); } } if (hashmap_status == ECMA_PROPERTY_HASHMAP_DELETE_RECREATE_HASHMAP) { ecma_property_hashmap_free (object_p); ecma_property_hashmap_create (object_p); } return new_length; } /* ecma_delete_array_properties */
/** * Free specified object */ void ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */ { JERRY_ASSERT (object_p != NULL && !ecma_gc_is_object_visited (object_p) && object_p->type_flags_refs < ECMA_OBJECT_REF_ONE); if (!ecma_is_lexical_environment (object_p)) { /* if the object provides free callback, invoke it with handle stored in the object */ ecma_external_pointer_t freecb_p; ecma_external_pointer_t native_p; bool is_retrieved = ecma_get_external_pointer_value (object_p, ECMA_INTERNAL_PROPERTY_FREE_CALLBACK, &freecb_p); if (is_retrieved && ((jerry_object_free_callback_t) freecb_p) != NULL) { is_retrieved = ecma_get_external_pointer_value (object_p, ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE, &native_p); JERRY_ASSERT (is_retrieved); jerry_dispatch_object_free_callback (freecb_p, native_p); } } if (!ecma_is_lexical_environment (object_p) || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); if (prop_iter_p != NULL && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_HASHMAP) { ecma_property_hashmap_free (object_p); prop_iter_p = ecma_get_property_list (object_p); } while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); /* Both cannot be deleted. */ JERRY_ASSERT (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED || prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED); ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED) { ecma_string_t *name_p = ECMA_GET_POINTER (ecma_string_t, prop_pair_p->names_cp[i]); ecma_free_property (object_p, name_p, prop_iter_p->types + i); if (name_p != NULL) { ecma_deref_ecma_string (name_p); } } } /* Both must be deleted. */ JERRY_ASSERT (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_DELETED && prop_iter_p->types[1] == ECMA_PROPERTY_TYPE_DELETED); prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); ecma_dealloc_property_pair (prop_pair_p); } } JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_number) > 0); JERRY_CONTEXT (ecma_gc_objects_number)--; if (!ecma_is_lexical_environment (object_p)) { if (ecma_get_object_is_builtin (object_p) || ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) { ecma_dealloc_extended_object ((ecma_extended_object_t *) object_p); return; } if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION) { /* Function with byte-code (not a built-in function). */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ext_func_p->u.function.bytecode_cp)); ecma_dealloc_extended_object (ext_func_p); return; } } ecma_dealloc_object (object_p); } /* ecma_gc_sweep */
/** * Delete the object's property referenced by its value pointer. * * Note: specified property must be owned by specified object. */ void ecma_delete_property (ecma_object_t *object_p, /**< object */ ecma_property_value_t *prop_value_p) /**< property value reference */ { ecma_property_header_t *cur_prop_p = ecma_get_property_list (object_p); ecma_property_header_t *prev_prop_p = NULL; ecma_property_hashmap_delete_status hashmap_status = ECMA_PROPERTY_HASHMAP_DELETE_NO_HASHMAP; if (cur_prop_p != NULL && cur_prop_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) { prev_prop_p = cur_prop_p; cur_prop_p = ECMA_GET_POINTER (ecma_property_header_t, cur_prop_p->next_property_cp); hashmap_status = ECMA_PROPERTY_HASHMAP_DELETE_HAS_HASHMAP; } while (true) { JERRY_ASSERT (cur_prop_p != NULL); JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (cur_prop_p)); ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) cur_prop_p; for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { if ((prop_pair_p->values + i) == prop_value_p) { JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (cur_prop_p->types[i]) != ECMA_PROPERTY_TYPE_SPECIAL); if (hashmap_status == ECMA_PROPERTY_HASHMAP_DELETE_HAS_HASHMAP) { hashmap_status = ecma_property_hashmap_delete (object_p, prop_pair_p->names_cp[i], cur_prop_p->types + i); } ecma_free_property (object_p, prop_pair_p->names_cp[i], cur_prop_p->types + i); JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2); if (cur_prop_p->types[1 - i] != ECMA_PROPERTY_TYPE_DELETED) { /* The other property is still valid. */ if (hashmap_status == ECMA_PROPERTY_HASHMAP_DELETE_RECREATE_HASHMAP) { ecma_property_hashmap_free (object_p); ecma_property_hashmap_create (object_p); } return; } JERRY_ASSERT (cur_prop_p->types[i] == ECMA_PROPERTY_TYPE_DELETED); if (prev_prop_p == NULL) { object_p->property_list_or_bound_object_cp = cur_prop_p->next_property_cp; } else { prev_prop_p->next_property_cp = cur_prop_p->next_property_cp; } ecma_dealloc_property_pair ((ecma_property_pair_t *) cur_prop_p); if (hashmap_status == ECMA_PROPERTY_HASHMAP_DELETE_RECREATE_HASHMAP) { ecma_property_hashmap_free (object_p); ecma_property_hashmap_create (object_p); } return; } } prev_prop_p = cur_prop_p; cur_prop_p = ECMA_GET_POINTER (ecma_property_header_t, cur_prop_p->next_property_cp); } } /* ecma_delete_property */