/** * ImplicitThisValue operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_implicit_this_value (ecma_object_t *lex_env_p) /**< lexical environment */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); if (ecma_get_lex_env_provide_this (lex_env_p)) { ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_ref_object (binding_obj_p); return ecma_make_object_value (binding_obj_p); } else { return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } } /* ecma_op_implicit_this_value */
/** * Get lexical environment's 'provideThis' property */ inline bool __attr_pure___ ecma_get_lex_env_provide_this (const ecma_object_t *object_p) /**< object-bound lexical environment */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (object_p)); JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); return ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND; } /* ecma_get_lex_env_provide_this */
/** * Resolve value corresponding to reference. * * @return value of the reference */ ecma_value_t ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical environment */ ecma_string_t *name_p, /**< identifier's name */ bool is_strict) /**< strict mode */ { JERRY_ASSERT (lex_env_p != NULL); while (lex_env_p != NULL) { if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); if (property_p != NULL) { ecma_value_t prop_value = ecma_get_named_data_property_value (property_p); /* is the binding mutable? */ if (unlikely (!ecma_is_property_writable (property_p) && ecma_is_value_empty (prop_value))) { /* unitialized mutable binding */ if (is_strict) { return ecma_raise_reference_error (ECMA_ERR_MSG ("")); } else { return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } return ecma_fast_copy_value (prop_value); } } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND || ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_property_t *property_p = ecma_op_object_get_property (binding_obj_p, name_p); if (property_p != NULL) { return ecma_op_object_get (binding_obj_p, name_p); } } lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p); } return ecma_raise_reference_error (ECMA_ERR_MSG ("")); } /* ecma_op_resolve_reference_value */
/** * CreateMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_deletable) /**< argument D */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_create_named_data_property (lex_env_p, name_p, true, false, is_deletable); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); { prop_desc.is_value_defined = true; prop_desc.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); prop_desc.is_writable_defined = true; prop_desc.is_writable = true; prop_desc.is_enumerable_defined = true; prop_desc.is_enumerable = true; prop_desc.is_configurable_defined = true; prop_desc.is_configurable = is_deletable; } ecma_completion_value_t completion = ecma_op_object_define_own_property (binding_obj_p, name_p, &prop_desc, true); if (ecma_is_completion_value_throw (completion)) { return completion; } else { JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (completion)); } } return ecma_make_empty_completion_value (); } /* ecma_op_create_mutable_binding */
/** * Get lexical environment's bound object. */ inline ecma_object_t *__attr_pure___ ecma_get_lex_env_binding_object (const ecma_object_t *object_p) /**< object-bound lexical environment */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (object_p)); JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); return ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->property_list_or_bound_object_cp); } /* ecma_get_lex_env_binding_object */
/** * CreateMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_deletable) /**< argument D */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE; if (is_deletable) { prop_attributes = (uint8_t) (prop_attributes | ECMA_PROPERTY_FLAG_CONFIGURABLE); } ecma_create_named_data_property (lex_env_p, name_p, prop_attributes, NULL); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_value_t completion; if (!ecma_get_object_extensible (binding_obj_p)) { return ECMA_VALUE_EMPTY; } completion = ecma_builtin_helper_def_prop (binding_obj_p, name_p, ECMA_VALUE_UNDEFINED, is_deletable ? ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE : ECMA_PROPERTY_ENUMERABLE_WRITABLE, true); /* Failure handling */ if (ECMA_IS_VALUE_ERROR (completion)) { return completion; } else { JERRY_ASSERT (ecma_is_value_boolean (completion)); } } return ECMA_VALUE_EMPTY; } /* ecma_op_create_mutable_binding */
/** * GetBindingValue operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_get_binding_value (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_strict) /**< argument S */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_t *property_p = ecma_get_named_data_property (lex_env_p, name_p); ecma_value_t prop_value = ecma_get_named_data_property_value (property_p); /* is the binding mutable? */ if (!ecma_is_property_writable (property_p) && ecma_is_value_empty (prop_value)) { /* unitialized immutable binding */ if (is_strict) { return ecma_raise_reference_error (""); } else { return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } return ecma_copy_value (prop_value, true); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); if (ecma_op_object_get_property (binding_obj_p, name_p) == NULL) { if (is_strict) { return ecma_raise_reference_error (""); } else { return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } return ecma_op_object_get (binding_obj_p, name_p); } } /* ecma_op_get_binding_value */
/** * Resolve syntactic reference. * * @return if reference was resolved successfully, * pointer to lexical environment - reference's base, * else - NULL. */ ecma_object_t * ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical environment */ ecma_string_t *name_p) /**< identifier's name */ { JERRY_ASSERT (lex_env_p != NULL); ecma_object_t *lex_env_iter_p = lex_env_p; while (lex_env_iter_p != NULL) { #if ENABLED (JERRY_ES2015_CLASS) if (ecma_get_lex_env_type (lex_env_iter_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND) { lex_env_iter_p = ecma_get_lex_env_outer_reference (lex_env_iter_p); JERRY_ASSERT (lex_env_iter_p != NULL); } #endif /* ENABLED (JERRY_ES2015_CLASS) */ if (ecma_op_has_binding (lex_env_iter_p, name_p)) { return lex_env_iter_p; } lex_env_iter_p = ecma_get_lex_env_outer_reference (lex_env_iter_p); } return NULL; } /* ecma_op_resolve_reference_base */
/** * SetMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ ecma_value_t value, /**< argument V */ bool is_strict) /**< argument S */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); JERRY_ASSERT (property_p != NULL && ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); if (ecma_is_property_writable (*property_p)) { ecma_named_data_property_assign_value (lex_env_p, ECMA_PROPERTY_VALUE_PTR (property_p), value); } else if (is_strict) { return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set.")); } } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_value_t completion = ecma_op_object_put (binding_obj_p, name_p, value, is_strict); if (ECMA_IS_VALUE_ERROR (completion)) { return completion; } JERRY_ASSERT (ecma_is_value_boolean (completion)); } return ECMA_VALUE_EMPTY; } /* ecma_op_set_mutable_binding */
/** * SetMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ ecma_value_t value, /**< argument V */ bool is_strict) /**< argument S */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_t *property_p = ecma_get_named_data_property (lex_env_p, name_p); if (ecma_is_property_writable (property_p)) { ecma_named_data_property_assign_value (lex_env_p, property_p, value); } else if (is_strict) { return ecma_raise_type_error (""); } } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_value_t completion = ecma_op_object_put (binding_obj_p, name_p, value, is_strict); if (ecma_is_value_error (completion)) { return completion; } else { JERRY_ASSERT (ecma_is_value_boolean (completion)); } } return ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); } /* ecma_op_set_mutable_binding */
/** * DeleteBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Return value is simple and so need not be freed. * However, ecma_free_value may be called for it, but it is a no-op. */ ecma_value_t ecma_op_delete_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p) /**< argument N */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, name_p); ecma_simple_value_t ret_val; if (prop_p == NULL) { ret_val = ECMA_SIMPLE_VALUE_TRUE; } else { JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA); if (!ecma_is_property_configurable (prop_p)) { ret_val = ECMA_SIMPLE_VALUE_FALSE; } else { ecma_delete_property (lex_env_p, prop_p); ret_val = ECMA_SIMPLE_VALUE_TRUE; } } return ecma_make_simple_value (ret_val); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); return ecma_op_object_delete (binding_obj_p, name_p, false); } } /* ecma_op_delete_binding */
/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p); if (lex_env_p != NULL) { ecma_gc_set_object_visited (lex_env_p, true); } if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); ecma_gc_set_object_visited (binding_object_p, true); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } } if (traverse_properties) { ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); if (prop_iter_p->types[0].type_and_flags != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 0); } if (prop_iter_p->types[1].type_and_flags != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 1); } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } } } /* ecma_gc_mark */
/** * Get object's/lexical environment's property list. * * See also: * ecma_op_object_get_property_names */ inline ecma_property_header_t *__attr_pure___ ecma_get_property_list (const ecma_object_t *object_p) /**< object or lexical environment */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (!ecma_is_lexical_environment (object_p) || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); return ECMA_GET_POINTER (ecma_property_header_t, object_p->property_list_or_bound_object_cp); } /* ecma_get_property_list */
/** * Set object's/lexical environment's property list. * * See also: * ecma_op_object_get_property_names */ static inline void ecma_set_property_list (ecma_object_t *object_p, /**< object or lexical environment */ ecma_property_header_t *property_list_p) /**< properties' list */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (!ecma_is_lexical_environment (object_p) || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); ECMA_SET_POINTER (object_p->property_list_or_bound_object_cp, property_list_p); } /* ecma_set_property_list */
/** * CreateMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_deletable) /**< argument D */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_create_named_data_property (lex_env_p, name_p, true, false, is_deletable); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_value_t completion; completion = ecma_builtin_helper_def_prop (binding_obj_p, name_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), true, /* Writable */ true, /* Enumerable */ is_deletable, /* Configurable */ true); /* Failure handling */ if (ecma_is_value_error (completion)) { return completion; } else { JERRY_ASSERT (ecma_is_value_boolean (completion)); } } return ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); } /* ecma_op_create_mutable_binding */
/** * HasBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return true / false */ bool ecma_op_has_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p) /**< argument N */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); return (property_p != NULL); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); return (ecma_op_object_get_property (binding_obj_p, name_p) != NULL); } } /* ecma_op_has_binding */
/** * GetBindingValue operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_get_binding_value (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_strict) /**< argument S */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_value_t *prop_value_p = ecma_get_named_data_property (lex_env_p, name_p); return ecma_copy_value (prop_value_p->value); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_value_t result = ecma_op_object_find (binding_obj_p, name_p); if (!ecma_is_value_found (result)) { if (is_strict) { result = ecma_raise_reference_error (ECMA_ERR_MSG ("Binding does not exist or is uninitialised.")); } else { result = ECMA_VALUE_UNDEFINED; } } return result; } } /* ecma_op_get_binding_value */
/** * Resolve super reference. * * @return value of the reference */ ecma_object_t * ecma_op_resolve_super_reference_value (ecma_object_t *lex_env_p) /**< starting lexical environment */ { while (true) { JERRY_ASSERT (lex_env_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND) { return ecma_get_lex_env_binding_object (lex_env_p); } lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p); } } /* ecma_op_resolve_super_reference_value */
/** * 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) && ecma_gc_get_object_refs (object_p) == 0); 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) { 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_OBJECTBOUND) { for (ecma_property_t *property = ecma_get_property_list (object_p), *next_property_p; property != NULL; property = next_property_p) { next_property_p = ECMA_GET_POINTER (ecma_property_t, property->next_property_p); ecma_free_property (object_p, property); } } JERRY_ASSERT (ecma_gc_objects_number > 0); ecma_gc_objects_number--; ecma_dealloc_object (object_p); } /* ecma_gc_sweep */
/** * InitializeImmutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 */ void ecma_op_initialize_immutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ ecma_value_t value) /**< argument V */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); ecma_property_t *prop_p = ecma_get_named_data_property (lex_env_p, name_p); /* The binding must be unitialized immutable binding */ JERRY_ASSERT (!ecma_is_property_writable (prop_p) && ecma_is_value_empty (ecma_get_named_data_property_value (prop_p))); ecma_named_data_property_assign_value (lex_env_p, prop_p, value); } /* ecma_op_initialize_immutable_binding */
/** * CreateImmutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 */ void ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ ecma_value_t value) /**< argument V */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); /* * Warning: * Whether immutable bindings are deletable seems not to be defined by ECMA v5. */ ecma_property_value_t *prop_value_p = ecma_create_named_data_property (lex_env_p, name_p, ECMA_PROPERTY_FIXED, NULL); prop_value_p->value = ecma_copy_value_if_not_object (value); } /* ecma_op_create_immutable_binding */
/** * CreateImmutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 */ void ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p) /**< argument N */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); /* * Warning: * Whether immutable bindings are deletable seems not to be defined by ECMA v5. */ ecma_property_t *prop_p = ecma_create_named_data_property (lex_env_p, name_p, false, false, false); JERRY_ASSERT (ecma_is_value_undefined (ecma_get_named_data_property_value (prop_p))); ecma_set_named_data_property_value (prop_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY)); } /* ecma_op_create_immutable_binding */
/** * SetMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ ecma_completion_value_t ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ ecma_value_t value, /**< argument V */ bool is_strict) /**< argument S */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { #ifndef JERRY_NDEBUG # ifdef CONFIG_ECMA_COMPACT_PROFILE bool is_equal = false; ecma_string_t *arguments_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); if (ecma_compare_ecma_strings (name_p, arguments_magic_string_p)) { is_equal = true; } ecma_deref_ecma_string (arguments_magic_string_p); JERRY_ASSERT (!is_equal); if (is_equal) { return ecma_make_throw_obj_completion_value (ecma_builtin_get (ECMA_BUILTIN_ID_COMPACT_PROFILE_ERROR)); } # endif /* CONFIG_ECMA_COMPACT_PROFILE */ #endif /* !JERRY_NDEBUG */ ecma_property_t *property_p = ecma_get_named_data_property (lex_env_p, name_p); if (ecma_is_property_writable (property_p)) { ecma_named_data_property_assign_value (lex_env_p, property_p, value); } else if (is_strict) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_completion_value_t completion = ecma_op_object_put (binding_obj_p, name_p, value, is_strict); if (ecma_is_completion_value_throw (completion)) { return completion; } else { JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (completion)); } } return ecma_make_empty_completion_value (); } /* ecma_op_set_mutable_binding */
/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p); if (lex_env_p != NULL) { ecma_gc_set_object_visited (lex_env_p, true); } if (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND) { ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); ecma_gc_set_object_visited (binding_object_p, true); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } } if (traverse_properties) { for (ecma_property_t *property_p = ecma_get_property_list (object_p), *next_property_p; property_p != NULL; property_p = next_property_p) { next_property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p); switch ((ecma_property_type_t) property_p->type) { case ECMA_PROPERTY_NAMEDDATA: { ecma_value_t value = ecma_get_named_data_property_value (property_p); if (ecma_is_value_object (value)) { ecma_object_t *value_obj_p = ecma_get_object_from_value (value); ecma_gc_set_object_visited (value_obj_p, true); } break; } case ECMA_PROPERTY_NAMEDACCESSOR: { ecma_object_t *getter_obj_p = ecma_get_named_accessor_property_getter (property_p); ecma_object_t *setter_obj_p = ecma_get_named_accessor_property_setter (property_p); if (getter_obj_p != NULL) { ecma_gc_set_object_visited (getter_obj_p, true); } if (setter_obj_p != NULL) { ecma_gc_set_object_visited (setter_obj_p, true); } break; } case ECMA_PROPERTY_INTERNAL: { ecma_internal_property_id_t property_id = (ecma_internal_property_id_t) property_p->u.internal_property.type; uint32_t property_value = property_p->u.internal_property.value; switch (property_id) { case ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES: /* a collection of ecma-values */ case ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES: /* a collection of ecma-values */ { JERRY_UNIMPLEMENTED ("Indexed array storage is not implemented yet."); } case ECMA_INTERNAL_PROPERTY_PROTOTYPE: /* the property's value is located in ecma_object_t (see above in the routine) */ case ECMA_INTERNAL_PROPERTY_EXTENSIBLE: /* the property's value is located in ecma_object_t (see above in the routine) */ case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type, * but number of the real internal property types */ { JERRY_UNREACHABLE (); } case ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS: /* a collection of strings */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE: /* compressed pointer to a ecma_string_t */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE: /* compressed pointer to a ecma_number_t */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE: /* a simple boolean value */ case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */ case ECMA_INTERNAL_PROPERTY_CODE_BYTECODE: /* compressed pointer to a bytecode array */ case ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET: /* an integer */ case ECMA_INTERNAL_PROPERTY_NATIVE_CODE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_FREE_CALLBACK: /* an object's native free callback */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_DESC: /* an integer */ case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_0_31: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_32_63: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS: { break; } case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */ case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */ { ecma_object_t *obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, property_value); ecma_gc_set_object_visited (obj_p, true); break; } } break; } } } } } /* ecma_gc_mark */
/** * Resolve value corresponding to reference. * * @return value of the reference */ ecma_value_t ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical environment */ ecma_string_t *name_p) /**< identifier's name */ { JERRY_ASSERT (lex_env_p != NULL); while (lex_env_p != NULL) { ecma_lexical_environment_type_t lex_env_type = ecma_get_lex_env_type (lex_env_p); if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); if (property_p != NULL) { return ecma_fast_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); } } else if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND) { ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); #ifndef CONFIG_ECMA_LCACHE_DISABLE ecma_property_t *property_p = ecma_lcache_lookup (binding_obj_p, name_p); if (property_p != NULL) { ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); if (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA) { return ecma_fast_copy_value (prop_value_p->value); } JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); ecma_object_t *getter_p = ecma_get_named_accessor_property_getter (prop_value_p); if (getter_p == NULL) { return ECMA_VALUE_UNDEFINED; } ecma_value_t base_value = ecma_make_object_value (binding_obj_p); return ecma_op_function_call (getter_p, base_value, NULL, 0); } #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ ecma_value_t prop_value = ecma_op_object_find (binding_obj_p, name_p); if (ecma_is_value_found (prop_value)) { return prop_value; } } else { #if ENABLED (JERRY_ES2015_CLASS) JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND); #else /* !ENABLED (JERRY_ES2015_CLASS) */ JERRY_UNREACHABLE (); #endif /* ENABLED (JERRY_ES2015_CLASS) */ } lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p); } #ifdef JERRY_ENABLE_ERROR_MESSAGES ecma_value_t name_val = ecma_make_string_value (name_p); ecma_value_t error_value = ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE, "% is not defined", name_val); #else /* !JERRY_ENABLE_ERROR_MESSAGES */ ecma_value_t error_value = ecma_raise_reference_error (NULL); #endif /* JERRY_ENABLE_ERROR_MESSAGES */ return error_value; } /* ecma_op_resolve_reference_value */
/** * 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) { 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); 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].type_and_flags != ECMA_PROPERTY_TYPE_DELETED || prop_iter_p->types[1].type_and_flags != 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].type_and_flags != 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].type_and_flags == ECMA_PROPERTY_TYPE_DELETED && prop_iter_p->types[1].type_and_flags == 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 (ecma_gc_objects_number > 0); ecma_gc_objects_number--; ecma_dealloc_object (object_p); } /* ecma_gc_sweep */
/** * GetBindingValue operation. * * See also: ECMA-262 v5, 10.2.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ ecma_completion_value_t ecma_op_get_binding_value (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_strict) /**< argument S */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { #ifndef JERRY_NDEBUG # ifdef CONFIG_ECMA_COMPACT_PROFILE bool is_equal = false; ecma_string_t *arguments_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); if (ecma_compare_ecma_strings (name_p, arguments_magic_string_p)) { is_equal = true; } ecma_deref_ecma_string (arguments_magic_string_p); JERRY_ASSERT (!is_equal); if (is_equal) { return ecma_make_throw_obj_completion_value (ecma_builtin_get (ECMA_BUILTIN_ID_COMPACT_PROFILE_ERROR)); } # endif /* CONFIG_ECMA_COMPACT_PROFILE */ #endif /* !JERRY_NDEBUG */ ecma_property_t *property_p = ecma_get_named_data_property (lex_env_p, name_p); ecma_value_t prop_value = ecma_get_named_data_property_value (property_p); /* is the binding mutable? */ if (!ecma_is_property_writable (property_p) && ecma_is_value_empty (prop_value)) { /* unitialized immutable binding */ if (is_strict) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_REFERENCE)); } else { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } return ecma_make_normal_completion_value (ecma_copy_value (prop_value, true)); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); if (ecma_op_object_get_property (binding_obj_p, name_p) == NULL) { if (is_strict) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_REFERENCE)); } else { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } return ecma_op_object_get (binding_obj_p, name_p); } } /* ecma_op_get_binding_value */
/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p); if (lex_env_p != NULL) { ecma_gc_set_object_visited (lex_env_p, true); } if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); ecma_gc_set_object_visited (binding_object_p, true); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } if (!ecma_get_object_is_builtin (object_p) && ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION) { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ext_func_p->u.function.scope_cp); ecma_gc_set_object_visited (scope_p, true); } } if (traverse_properties) { 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) { prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); if (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 0); } if (prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 1); } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } } } /* ecma_gc_mark */
/** * 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 */
/** * 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 */