diff --git a/jerry-core/ecma/base/ecma-gc.cpp b/jerry-core/ecma/base/ecma-gc.cpp index 30e72526c8..2edd99912b 100644 --- a/jerry-core/ecma/base/ecma-gc.cpp +++ b/jerry-core/ecma/base/ecma-gc.cpp @@ -34,6 +34,9 @@ #include "jrt-libc-includes.h" #include "jrt-bit-fields.h" +#define JERRY_INTERNAL +#include "jerry-internal.h" + /** * An object's GC color * @@ -320,6 +323,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ case ECMA_INTERNAL_PROPERTY_CODE: /* 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_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */ @@ -357,6 +361,27 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */ && !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) { diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index b8cd218138..03e467cbc5 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -206,6 +206,7 @@ typedef enum ECMA_INTERNAL_PROPERTY_CODE, /**< [[Code]] */ ECMA_INTERNAL_PROPERTY_NATIVE_CODE, /**< native handler location descriptor */ ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE, /**< native handle associated with an object */ + ECMA_INTERNAL_PROPERTY_FREE_CALLBACK, /**< object's native free callback */ ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS, /**< [[FormalParameters]] */ ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE, /**< [[Primitive value]] for String objects */ ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE, /**< [[Primitive value]] for Number objects */ diff --git a/jerry-core/ecma/base/ecma-helpers-external-pointers.cpp b/jerry-core/ecma/base/ecma-helpers-external-pointers.cpp index 779ff8bf34..91ddbc9114 100644 --- a/jerry-core/ecma/base/ecma-helpers-external-pointers.cpp +++ b/jerry-core/ecma/base/ecma-helpers-external-pointers.cpp @@ -30,7 +30,8 @@ * Note: * property identifier should be one of the following: * - ECMA_INTERNAL_PROPERTY_NATIVE_CODE; - * - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE. + * - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE; + * - ECMA_INTERNAL_PROPERTY_FREE_CALLBACK. * * @return true - if property was just created with specified value, * false - otherwise, if property existed before the call, it's value was updated. @@ -42,7 +43,8 @@ ecma_create_external_pointer_property (ecma_object_t *obj_p, /**< object to crea ecma_external_pointer_t ptr_value) /**< value to store in the property */ { JERRY_ASSERT (id == ECMA_INTERNAL_PROPERTY_NATIVE_CODE - || id == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE); + || id == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE + || id == ECMA_INTERNAL_PROPERTY_FREE_CALLBACK); bool ret_val; ecma_property_t *prop_p = ecma_find_internal_property (obj_p, id); @@ -81,7 +83,8 @@ ecma_create_external_pointer_property (ecma_object_t *obj_p, /**< object to crea * Note: * property identifier should be one of the following: * - ECMA_INTERNAL_PROPERTY_NATIVE_CODE; - * - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE. + * - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE; + * - ECMA_INTERNAL_PROPERTY_FREE_CALLBACK. * * @return true - if property exists and it's value is returned through out_pointer_p, * false - otherwise (value returned through out_pointer_p is NULL). @@ -93,7 +96,8 @@ ecma_get_external_pointer_value (ecma_object_t *obj_p, /**< object to get proper ecma_external_pointer_t *out_pointer_p) /**< out: value of the external pointer */ { JERRY_ASSERT (id == ECMA_INTERNAL_PROPERTY_NATIVE_CODE - || id == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE); + || id == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE + || id == ECMA_INTERNAL_PROPERTY_FREE_CALLBACK); ecma_property_t* prop_p = ecma_find_internal_property (obj_p, id); @@ -126,13 +130,15 @@ ecma_get_external_pointer_value (ecma_object_t *obj_p, /**< object to get proper * Note: * property identifier should be one of the following: * - ECMA_INTERNAL_PROPERTY_NATIVE_CODE; - * - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE. + * - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE; + * - ECMA_INTERNAL_PROPERTY_FREE_CALLBACK. */ void ecma_free_external_pointer_in_property (ecma_property_t *prop_p) /**< internal property */ { JERRY_ASSERT (prop_p->u.internal_property.type == ECMA_INTERNAL_PROPERTY_NATIVE_CODE - || prop_p->u.internal_property.type == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE); + || prop_p->u.internal_property.type == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE + || prop_p->u.internal_property.type == ECMA_INTERNAL_PROPERTY_FREE_CALLBACK); if (sizeof (ecma_external_pointer_t) == sizeof (uint32_t)) { diff --git a/jerry-core/ecma/base/ecma-helpers.cpp b/jerry-core/ecma/base/ecma-helpers.cpp index 454a8e2e9a..114f33f4ce 100644 --- a/jerry-core/ecma/base/ecma-helpers.cpp +++ b/jerry-core/ecma/base/ecma-helpers.cpp @@ -780,6 +780,7 @@ ecma_free_internal_property (ecma_property_t *property_p) /**< the property */ 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 external pointer */ { ecma_free_external_pointer_in_property (property_p); diff --git a/jerry-core/jerry-api.h b/jerry-core/jerry-api.h index ec0c11d20a..a3ca9f3993 100644 --- a/jerry-core/jerry-api.h +++ b/jerry-core/jerry-api.h @@ -100,6 +100,11 @@ typedef bool (*jerry_external_handler_t) (const jerry_api_object_t *function_obj const jerry_api_value_t args_p [], const uint16_t args_count); +/** + * An object's native free callback + */ +typedef void (*jerry_object_free_callback_t) (const uintptr_t native_p); + extern EXTERN_C ssize_t jerry_api_string_to_char_buffer (const jerry_api_string_t *string_p, char *buffer_p, @@ -152,6 +157,10 @@ bool jerry_api_get_object_native_handle (jerry_api_object_t *object_p, uintptr_t extern EXTERN_C void jerry_api_set_object_native_handle (jerry_api_object_t *object_p, uintptr_t handle); +extern EXTERN_C +bool jerry_api_set_object_free_callback (jerry_api_object_t *object_p, + jerry_object_free_callback_t freecb_p); + extern EXTERN_C bool jerry_api_call_function (jerry_api_object_t *function_object_p, jerry_api_object_t *this_arg_p, diff --git a/jerry-core/jerry-internal.h b/jerry-core/jerry-internal.h index 9b0ce67a1f..8567dfc2b8 100644 --- a/jerry-core/jerry-internal.h +++ b/jerry-core/jerry-internal.h @@ -30,4 +30,8 @@ jerry_dispatch_external_function (ecma_object_t *function_object_p, const ecma_value_t args_p [], ecma_length_t args_count); +extern void +jerry_dispatch_object_free_callback (ecma_external_pointer_t freecb_p, + ecma_external_pointer_t native_p); + #endif /* !JERRY_INTERNAL_H */ diff --git a/jerry-core/jerry.cpp b/jerry-core/jerry.cpp index 6afe6130a1..dea32118c9 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -499,6 +499,25 @@ jerry_dispatch_external_function (ecma_object_t *function_object_p, /**< externa return completion_value; } /* jerry_dispatch_external_function */ +/** + * Dispatch call to object's native free callback function + * + * Note: + * the callback is called during critical GC phase, + * so, should not perform any requests to engine + */ +void +jerry_dispatch_object_free_callback (ecma_external_pointer_t freecb_p, /**< pointer to free callback handler */ + ecma_external_pointer_t native_p) /**< native handle, associated + * with freed object */ +{ + jerry_make_api_unavailable (); + + ((jerry_object_free_callback_t) freecb_p) ((uintptr_t) native_p); + + jerry_make_api_available (); +} /* jerry_dispatch_object_free_callback */ + /** * Check if the specified object is a function object. * @@ -743,6 +762,32 @@ jerry_api_set_object_native_handle (jerry_api_object_t *object_p, /**< object to handle); } /* jerry_api_set_object_native_handle */ +/** + * Set object free callback for the specified object + * + * @return true - if callback was set successfully, + * false - otherwise (there is no native handle, associated with the object). + */ +bool +jerry_api_set_object_free_callback (jerry_api_object_t *object_p, /**< object to set callback for */ + jerry_object_free_callback_t freecb_p) /**< object free callback */ +{ + uintptr_t handle_value; + bool is_native_handle_associated = jerry_api_get_object_native_handle (object_p, + &handle_value); + + if (!is_native_handle_associated) + { + return false; + } + + ecma_create_external_pointer_property (object_p, + ECMA_INTERNAL_PROPERTY_FREE_CALLBACK, + (uintptr_t) freecb_p); + + return true; +} /* jerry_api_set_object_free_callback */ + /** * Invoke function specified by a function object * @@ -1019,7 +1064,6 @@ jerry_init (jerry_flag_t flags) /**< combination of Jerry flags */ jerry_flags = flags; - jerry_make_api_unavailable (); /* TODO remove this line when it's called somewhere else */ jerry_make_api_available (); mem_init (); diff --git a/tests/unit/test_api.cpp b/tests/unit/test_api.cpp index 869edc9f8b..663261993c 100644 --- a/tests/unit/test_api.cpp +++ b/tests/unit/test_api.cpp @@ -40,6 +40,8 @@ const char *test_source = ( "}" ); +bool test_api_is_free_callback_was_called = false; + /** * Initialize Jerry API value with specified boolean value */ @@ -115,6 +117,15 @@ handler (const jerry_api_object_t *function_obj_p, return true; } /* handler */ +static void +handler_construct_freecb (uintptr_t native_p) +{ + assert (native_p == (uintptr_t) 0x0012345678abcdefull); + printf ("ok object free callback\n"); + + test_api_is_free_callback_was_called = true; +} /* handler_construct_freecb */ + static bool handler_construct (const jerry_api_object_t *function_obj_p, const jerry_api_value_t *this_p, @@ -135,6 +146,9 @@ handler_construct (const jerry_api_object_t *function_obj_p, jerry_api_set_object_native_handle (this_p->v_object, (uintptr_t) 0x0012345678abcdefull); + bool is_set = jerry_api_set_object_free_callback (this_p->v_object, handler_construct_freecb); + assert (is_set); + return true; } /* handler_construct */