diff --git a/jerry-core/ecma/base/ecma-gc.cpp b/jerry-core/ecma/base/ecma-gc.cpp index 30e72526c8..8889cc8b0c 100644 --- a/jerry-core/ecma/base/ecma-gc.cpp +++ b/jerry-core/ecma/base/ecma-gc.cpp @@ -34,6 +34,10 @@ #include "jrt-libc-includes.h" #include "jrt-bit-fields.h" +#define JERRY_INTERNAL +#include "jerry-internal.h" + + /** * An object's GC color * @@ -320,6 +324,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 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 */ @@ -360,6 +365,26 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */ if (!ecma_is_lexical_environment (object_p) || ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND) { + /* call object free callback with given handle */ + if (!ecma_is_lexical_environment (object_p)) + { + 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 && freecb_p) + is_retrieved = + ecma_get_external_pointer_value (object_p, + ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE, + &native_p); + + if (is_retrieved && native_p) + jerry_dispatch_object_free_callback (freecb_p, native_p); + } + for (ecma_property_t *property = ecma_get_property_list (object_p), *next_property_p; property != NULL; property = next_property_p) diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index b8cd218138..1aee268b7e 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, /**< native free callback associated with an object */ 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..f9f035423f 100644 --- a/jerry-core/jerry-api.h +++ b/jerry-core/jerry-api.h @@ -100,6 +100,9 @@ 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); +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 +155,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 +void 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..926d87a6a2 100644 --- a/jerry-core/jerry-internal.h +++ b/jerry-core/jerry-internal.h @@ -30,4 +30,9 @@ 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 4220bf1c7c..d42edb27f7 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -424,6 +424,20 @@ jerry_dispatch_external_function (ecma_object_t *function_object_p, /**< externa return completion_value; } /* jerry_dispatch_external_function */ +/** + * Dispatch call to object free callback function + * + * Note: + * it's critical GC phase so should not re-enter jerry apis + */ +void +jerry_dispatch_object_free_callback (ecma_external_pointer_t freecb_p, /**< pointer to free callback handler */ + ecma_external_pointer_t native_p) /**< pointer to the function's native handler */ +{ + /* Todo: prevent call inside jerry again */ + ((jerry_object_free_callback_t) freecb_p) ((uintptr_t)native_p); +} + /** * Check if the specified object is a function object. * @@ -652,6 +666,18 @@ 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 native handle for the specified object + */ +void +jerry_api_set_object_free_callback (jerry_api_object_t *object_p, /**< object to set handle in */ + jerry_object_free_callback_t freecb_p) /**< free callback function */ +{ + ecma_create_external_pointer_property (object_p, + ECMA_INTERNAL_PROPERTY_FREE_CALLBACK, + (uintptr_t)freecb_p); +} /* jerry_api_set_object_freecb_handle */ + /** * Invoke function specified by a function object * diff --git a/tests/unit/test_api.cpp b/tests/unit/test_api.cpp index 869edc9f8b..8c70536516 100644 --- a/tests/unit/test_api.cpp +++ b/tests/unit/test_api.cpp @@ -115,6 +115,13 @@ 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"); +} + static bool handler_construct (const jerry_api_object_t *function_obj_p, const jerry_api_value_t *this_p, @@ -135,6 +142,8 @@ handler_construct (const jerry_api_object_t *function_obj_p, jerry_api_set_object_native_handle (this_p->v_object, (uintptr_t) 0x0012345678abcdefull); + jerry_api_set_object_free_callback (this_p->v_object, handler_construct_freecb); + return true; } /* handler_construct */