From e522e740a7949251c378e2e3e2ee531c1fcc7391 Mon Sep 17 00:00:00 2001 From: Zidong Jiang Date: Mon, 10 Apr 2017 16:51:37 +0800 Subject: [PATCH] Add 'type' argument to set/get native handle API (#1711) Ecma-object have native handle type inside, and binding code could use type info to validate native handle's type. Related issue #1681 JerryScript-DCO-1.0-Signed-off-by: Zidong Jiang zidong.jiang@intel.com --- docs/02.API-REFERENCE.md | 180 +++++++++++++++++- jerry-core/ecma/base/ecma-alloc.c | 1 - jerry-core/ecma/base/ecma-alloc.h | 12 -- jerry-core/ecma/base/ecma-gc.c | 76 +++++--- jerry-core/ecma/base/ecma-globals.h | 22 +++ .../base/ecma-helpers-external-pointers.c | 141 ++++++++------ jerry-core/ecma/base/ecma-helpers.c | 4 +- jerry-core/ecma/base/ecma-helpers.h | 16 +- jerry-core/jerry.c | 86 +++++++-- jerry-core/jerryscript.h | 30 ++- jerry-core/lit/lit-magic-strings.h | 7 +- tests/unit/test-api.c | 52 +++-- 12 files changed, 486 insertions(+), 141 deletions(-) diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 69f24fb0f..80621c14f 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -167,7 +167,9 @@ typedef jerry_value_t (*jerry_external_handler_t) (const jerry_value_t function_ **Summary** -Native free callback of an object +**Deprecated: Please use jerry_object_native_free_callback_t instead.** + +Native free callback of an object. **Prototype** @@ -175,6 +177,34 @@ Native free callback of an object typedef void (*jerry_object_free_callback_t) (const uintptr_t native_p); ``` +## jerry_object_native_free_callback_t + +**Summary** + +Native free callback of an object. It is used in jerry_object_native_info_t. + +**Prototype** + +```c +typedef void (*jerry_object_native_free_callback_t) (void *native_p); +``` + +## jerry_object_native_info_t + +**Summary** + +The type infomation of the native pointer. +It includes the free callback that will be called when associated JavaScript object is garbage collected. It can be left NULL in case it is not needed. + +**Prototype** + +```c +typedef struct +{ + jerry_object_native_free_callback_t free_cb; +} jerry_object_native_info_t; +``` + ## jerry_object_property_foreach_t **Summary** @@ -3173,6 +3203,8 @@ jerry_set_prototype (const jerry_value_t obj_val, **Summary** +**Deprecated: Please use jerry_get_object_native_pointer instead.** + Get native handle, previously associated with specified object. **Prototype** @@ -3211,12 +3243,16 @@ jerry_get_object_native_handle (const jerry_value_t obj_val, - [jerry_create_object](#jerry_create_object) - [jerry_set_object_native_handle](#jerry_set_object_native_handle) +- [jerry_get_object_native_pointer](#jerry_get_object_native_pointer) + ## jerry_set_object_native_handle **Summary** -Set native handle and an optional free callback for the specified object +**Deprecated: Please use jerry_set_object_native_pointer instead.** + +Set native handle and an optional free callback for the specified object. *Note*: If native handle was already set for the object, its value is updated. @@ -3260,6 +3296,146 @@ jerry_set_object_native_handle (const jerry_value_t obj_val, - [jerry_create_object](#jerry_create_object) - [jerry_get_object_native_handle](#jerry_get_object_native_handle) +- [jerry_set_object_native_pointer](#jerry_set_object_native_pointer) + + +## jerry_get_object_native_pointer + +**Summary** + +Get native pointer and its type information. +The pointer and the type information are previously associated with the object by jerry_set_object_native_pointer. +Users can check the pointer's type before processing it. + +**Prototype** + +```c +bool +jerry_get_object_native_pointer (const jerry_value_t obj_val, + void **out_native_p, + const jerry_object_native_info_t **out_info_p) +``` + +- `obj_val` - object value to get native pointer from. +- `out_native_p` - native pointer (output parameter). +- `out_info_p` - native pointer's type infomation (output parameter). +- return value + - true, if there is native pointer associated with the object + - false, otherwise + +**Example** + +```c +static void native_freecb (uintptr_t native_p) +{ + ... // free the native pointer +} + +static const jerry_object_native_info_t type_info = +{ + .free_cb = native_freecb +}; + +{ + jerry_value_t object; + uintptr_t native_set; + + ... // receive or construct object and native_set value + + jerry_set_object_native_pointer (object, native_set, &type_info); + + ... + + uintptr_t native_get; + const jerry_object_native_info_t *type_get_p; + bool is_there_associated_native = jerry_get_object_native_pointer (object, &native_get, &type_get_p); + + if (is_there_associated_native) + { + if (out_info_p == &type_info) + { + ... // the type of object's native pointer is expected, and then process the native pointer. + } + } +} +``` + +**See also** + +- [jerry_create_object](#jerry_create_object) +- [jerry_set_object_native_pointer](#jerry_set_object_native_pointer) +- [jerry_object_native_info_t](#jerry_object_native_info_t) + + +## jerry_set_object_native_pointer + +**Summary** + +Set native pointer and an optional type information for the specified object. +You can get them by calling jerry_get_object_native_pointer later. + +*Note*: If native pointer was already set for the object, its value is updated. + +*Note*: If a non-NULL free callback is specified in the native type information, + it will be called by the garbage collector when the object is freed. + The type info is always overwrites the previous value, so passing + a NULL value deletes the current type info. + +**Prototype** + +```c +bool +jerry_set_object_native_pointer (const jerry_value_t obj_val, + void *native_p, + const jerry_object_native_info_t *info_p) +``` + +- `obj_val` - object to set native pointer in. +- `native_p` - native pointer. +- `info_p` - native pointer's type infomation or NULL. + +**Example** + +```c +static void native_freecb (uintptr_t native_p) +{ + ... // free the native pointer +} + +static const jerry_object_native_info_t type_info = +{ + .free_cb = native_freecb +}; + +{ + jerry_value_t object; + uintptr_t native_set; + + ... // receive or construct object and native_set value + + jerry_set_object_native_pointer (object, native_set, &type_info); + + ... + + uintptr_t native_get; + const jerry_object_native_info_t *type_get_p; + bool is_there_associated_native = jerry_get_object_native_pointer (object, &native_get, &type_get_p); + + if (is_there_associated_native) + { + if (out_info_p == &type_info) + { + ... // the type of object's native pointer is expected, and then process the native pointer. + } + } +} +``` + +**See also** + +- [jerry_create_object](#jerry_create_object) +- [jerry_get_object_native_pointer](#jerry_get_object_native_pointer) +- [jerry_object_native_info_t](#jerry_object_native_info_t) ## jerry_foreach_object_property diff --git a/jerry-core/ecma/base/ecma-alloc.c b/jerry-core/ecma/base/ecma-alloc.c index dae9f6ad4..3bbcdf275 100644 --- a/jerry-core/ecma/base/ecma-alloc.c +++ b/jerry-core/ecma/base/ecma-alloc.c @@ -86,7 +86,6 @@ DECLARE_ROUTINES_FOR (collection_header) DECLARE_ROUTINES_FOR (collection_chunk) DECLARE_ROUTINES_FOR (string) DECLARE_ROUTINES_FOR (getter_setter_pointers) -DECLARE_ROUTINES_FOR (external_pointer) /** * Allocate memory for extended object diff --git a/jerry-core/ecma/base/ecma-alloc.h b/jerry-core/ecma/base/ecma-alloc.h index 84833376a..435ed54c2 100644 --- a/jerry-core/ecma/base/ecma-alloc.h +++ b/jerry-core/ecma/base/ecma-alloc.h @@ -97,18 +97,6 @@ ecma_getter_setter_pointers_t *ecma_alloc_getter_setter_pointers (void); */ void ecma_dealloc_getter_setter_pointers (ecma_getter_setter_pointers_t *getter_setter_pointers_p); -/** -* Allocate memory for external pointer -* -* @return pointer to allocated memory -*/ -ecma_external_pointer_t *ecma_alloc_external_pointer (void); - -/** -* Dealloc memory from external pointer -*/ -void ecma_dealloc_external_pointer (ecma_external_pointer_t *external_pointer_p); - /* * Allocate memory for extended object * diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index d0de5a41c..cdb8c3b1b 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -353,6 +353,47 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ } } /* ecma_gc_mark */ +/** + * Free the native handle/pointer by calling its free callback + */ +static void +ecma_gc_free_native_pointer (ecma_property_t *property_p, /**< property */ + lit_magic_string_id_t id) /**< identifier of internal property */ +{ + JERRY_ASSERT (property_p != NULL); + + JERRY_ASSERT (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE + || id == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); + + ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + ecma_external_pointer_t native_p; + ecma_external_pointer_t free_cb; + void *package_p; + + package_p = ECMA_GET_INTERNAL_VALUE_POINTER (void, value_p->value); + + if (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE) + { + native_p = ((ecma_native_handle_package_t *) package_p)->handle_p; + free_cb = ((ecma_native_handle_package_t *) package_p)->free_cb; + + if ((jerry_object_free_callback_t) free_cb != NULL) + { + ((jerry_object_free_callback_t) free_cb) ((uintptr_t) native_p); + } + } + else + { + native_p = ((ecma_native_pointer_package_t *) package_p)->native_p; + free_cb = *(ecma_external_pointer_t *) (((ecma_native_pointer_package_t *) package_p)->info_p); + + if ((jerry_object_native_free_callback_t) free_cb != NULL) + { + ((jerry_object_native_free_callback_t) free_cb) ((void *) native_p); + } + } +} /* ecma_gc_free_native_pointer */ + /** * Free specified object */ @@ -365,28 +406,6 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */ bool obj_is_not_lex_env = !ecma_is_lexical_environment (object_p); - if (obj_is_not_lex_env) - { - /* 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, - LIT_INTERNAL_MAGIC_STRING_FREE_CALLBACK, - &freecb_p); - - if (is_retrieved && ((jerry_object_free_callback_t) freecb_p) != NULL) - { - is_retrieved = ecma_get_external_pointer_value (object_p, - LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE, - &native_p); - JERRY_ASSERT (is_retrieved); - - jerry_dispatch_object_free_callback (freecb_p, native_p); - } - } - if (obj_is_not_lex_env || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { @@ -410,9 +429,20 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */ for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { + ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); + jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; + + /* Call the native's free callback. */ + if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_STRING_CONTAINER_MAGIC_STRING + && (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE + || name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER)) + { + ecma_gc_free_native_pointer (property_p, (lit_magic_string_id_t) name_cp); + } + if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED) { - ecma_free_property (object_p, prop_pair_p->names_cp[i], prop_iter_p->types + i); + ecma_free_property (object_p, name_cp, property_p); } } diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 5b3647b49..eb8002203 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -195,6 +195,28 @@ typedef int32_t ecma_integer_value_t; */ typedef uintptr_t ecma_external_pointer_t; +/** + * Representation for native handle package. + * + * Note: It is for the deprecated api: + * jerry_get_object_native_handle and jerry_set_object_native_handle + */ + +typedef struct +{ + ecma_external_pointer_t handle_p; /**< points to the external native object */ + ecma_external_pointer_t free_cb; /**< free callback of the native handle */ +} ecma_native_handle_package_t; + +/** + * Representation of the native pointer package. + */ +typedef struct +{ + ecma_external_pointer_t native_p; /**< points to the external native object */ + ecma_external_pointer_t info_p; /**< type info of the native pointer */ +} ecma_native_pointer_package_t; + /** * Special property identifiers. */ diff --git a/jerry-core/ecma/base/ecma-helpers-external-pointers.c b/jerry-core/ecma/base/ecma-helpers-external-pointers.c index 1e176a0a0..5b2b07837 100644 --- a/jerry-core/ecma/base/ecma-helpers-external-pointers.c +++ b/jerry-core/ecma/base/ecma-helpers-external-pointers.c @@ -25,24 +25,24 @@ */ /** - * Create internal property with specified identifier and store external pointer in the property. + * Create internal property with specified identifier and store native handle/pointer of the object. * * Note: * property identifier should be one of the following: * - LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE - * - LIT_INTERNAL_MAGIC_STRING_FREE_CALLBACK + * - LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER * * @return true - if property was just created with specified value, * false - otherwise, if property existed before the call, it's value was updated */ -bool -ecma_create_external_pointer_property (ecma_object_t *obj_p, /**< object to create property in */ - lit_magic_string_id_t id, /**< identifier of internal - * property to create */ - ecma_external_pointer_t ptr_value) /**< value to store in the property */ +static bool +ecma_create_native_property (ecma_object_t *obj_p, /**< object to create property in */ + lit_magic_string_id_t id, /**< identifier of internal + * property to create */ + void *package_p) /**< value to store in the property */ { JERRY_ASSERT (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE - || id == LIT_INTERNAL_MAGIC_STRING_FREE_CALLBACK); + || id == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); ecma_string_t name; ecma_init_ecma_magic_string (&name, id); @@ -58,6 +58,7 @@ ecma_create_external_pointer_property (ecma_object_t *obj_p, /**< object to crea else { value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + ecma_free_native_package_property (property_p, id); } JERRY_ASSERT (ECMA_STRING_IS_REF_EQUALS_TO_ONE (&name)); @@ -65,51 +66,72 @@ ecma_create_external_pointer_property (ecma_object_t *obj_p, /**< object to crea JERRY_STATIC_ASSERT (sizeof (uint32_t) <= sizeof (value_p->value), size_of_internal_property_value_must_be_greater_than_or_equal_to_4_bytes); -#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY - - value_p->value = (ecma_value_t) ptr_value; - -#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ - - ecma_external_pointer_t *handler_p; - - if (is_new) - { - handler_p = ecma_alloc_external_pointer (); - - ECMA_SET_NON_NULL_POINTER (value_p->value, handler_p); - } - else - { - handler_p = ECMA_GET_NON_NULL_POINTER (ecma_external_pointer_t, value_p->value); - } - - *handler_p = ptr_value; - -#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ + ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, package_p); return is_new; -} /* ecma_create_external_pointer_property */ +} /* ecma_create_native_property */ /** - * Get value of external pointer stored in the object's property with specified identifier + * Create a native handle property to store the native handle and its 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 + */ +bool +ecma_create_native_handle_property (ecma_object_t *obj_p, /**< object to create property in */ + ecma_external_pointer_t handle_p, /**< native handle */ + ecma_external_pointer_t free_cb) /**< native handle's free callback*/ +{ + ecma_native_handle_package_t *package_p; + package_p = jmem_heap_alloc_block (sizeof (ecma_native_handle_package_t)); + package_p->handle_p = handle_p; + package_p->free_cb = free_cb; + + return ecma_create_native_property (obj_p, + LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE, + package_p); +} /* ecma_create_native_handle_property */ + +/** + * Create a native pointer property to store the native pointer and its type info. + * + * @return true - if property was just created with specified value, + * false - otherwise, if property existed before the call, it's value was updated + */ +bool +ecma_create_native_pointer_property (ecma_object_t *obj_p, /**< object to create property in */ + ecma_external_pointer_t native_p, /**< native pointer */ + ecma_external_pointer_t info_p) /**< native pointer's type info */ +{ + ecma_native_pointer_package_t *package_p; + package_p = jmem_heap_alloc_block (sizeof (ecma_native_pointer_package_t)); + package_p->native_p = native_p; + package_p->info_p = info_p; + + return ecma_create_native_property (obj_p, + LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, + package_p); +} /* ecma_create_native_pointer_property */ + +/** + * Get value of native package stored in the object's property with specified identifier * * Note: * property identifier should be one of the following: * - LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE - * - LIT_INTERNAL_MAGIC_STRING_FREE_CALLBACK + * - LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER * * @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) */ bool -ecma_get_external_pointer_value (ecma_object_t *obj_p, /**< object to get property value from */ - lit_magic_string_id_t id, /**< identifier of internal property - * to get value from */ - ecma_external_pointer_t *out_pointer_p) /**< [out] value of the external pointer */ +ecma_get_native_package_value (ecma_object_t *obj_p, /**< object to get property value from */ + lit_magic_string_id_t id, /**< identifier of internal property + * to get value from */ + void **out_pointer_p) /**< [out] value of the native package */ { JERRY_ASSERT (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE - || id == LIT_INTERNAL_MAGIC_STRING_FREE_CALLBACK); + || id == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); ecma_string_t name; ecma_init_ecma_magic_string (&name, id); @@ -120,51 +142,46 @@ ecma_get_external_pointer_value (ecma_object_t *obj_p, /**< object to get proper if (property_p == NULL) { - *out_pointer_p = (ecma_external_pointer_t) NULL; + *out_pointer_p = NULL; return false; } ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p); -#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY - - *out_pointer_p = value_p->value; - -#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ - - *out_pointer_p = *ECMA_GET_NON_NULL_POINTER (ecma_external_pointer_t, value_p->value); - -#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ + *out_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (void, value_p->value); return true; -} /* ecma_get_external_pointer_value */ +} /* ecma_get_native_package_value */ /** - * Free memory associated with external pointer stored in the property + * Free the allocated native package struct. * * Note: * property identifier should be one of the following: * - LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE - * - LIT_INTERNAL_MAGIC_STRING_FREE_CALLBACK + * - LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER */ void -ecma_free_external_pointer_in_property (ecma_property_t *prop_p) /**< internal property */ +ecma_free_native_package_property (ecma_property_t *prop_p, /**< native property */ + lit_magic_string_id_t id) /**< identifier of internal */ { -#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY + JERRY_ASSERT (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE + || id == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); - /* no additional memory was allocated for the pointer storage */ - JERRY_UNUSED (prop_p); + ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (prop_p); + void *package_p; -#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ + package_p = ECMA_GET_INTERNAL_VALUE_POINTER (void, value_p->value); - ecma_external_pointer_t *handler_p = ECMA_GET_NON_NULL_POINTER (ecma_external_pointer_t, - ECMA_PROPERTY_VALUE_PTR (prop_p)->value); + if (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE) + { + jmem_heap_free_block (package_p, sizeof (ecma_native_handle_package_t)); + return; + } - ecma_dealloc_external_pointer (handler_p); - -#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ -} /* ecma_free_external_pointer_in_property */ + jmem_heap_free_block (package_p, sizeof (ecma_native_pointer_package_t)); +} /* ecma_free_native_package_property */ /** * @} diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index dd0899038..ca13f1af5 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -731,9 +731,9 @@ ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_STRING_CONTAINER_MAGIC_STRING) { if (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE - || name_cp == LIT_INTERNAL_MAGIC_STRING_FREE_CALLBACK) + || name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER) { - ecma_free_external_pointer_in_property (property_p); + ecma_free_native_package_property (property_p, (lit_magic_string_id_t) name_cp); break; } } diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 3bbc9f021..feee16930 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -341,11 +341,17 @@ void ecma_bytecode_ref (ecma_compiled_code_t *bytecode_p); void ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p); /* ecma-helpers-external-pointers.c */ -bool ecma_create_external_pointer_property (ecma_object_t *obj_p, lit_magic_string_id_t id, - ecma_external_pointer_t ptr_value); -bool ecma_get_external_pointer_value (ecma_object_t *obj_p, lit_magic_string_id_t id, - ecma_external_pointer_t *out_pointer_p); -void ecma_free_external_pointer_in_property (ecma_property_t *prop_p); +bool ecma_create_native_handle_property (ecma_object_t *obj_p, + ecma_external_pointer_t handle_p, + ecma_external_pointer_t free_cb); +bool ecma_create_native_pointer_property (ecma_object_t *obj_p, + ecma_external_pointer_t native_p, + ecma_external_pointer_t info_p); +bool ecma_get_native_package_value (ecma_object_t *obj_p, + lit_magic_string_id_t id, + void **out_pointer_p); +void ecma_free_native_package_property (ecma_property_t *prop_p, + lit_magic_string_id_t id); /* ecma-helpers-conversion.c */ ecma_number_t ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, lit_utf8_size_t str_size); diff --git a/jerry-core/jerry.c b/jerry-core/jerry.c index 910888784..0d594fdf5 100644 --- a/jerry-core/jerry.c +++ b/jerry-core/jerry.c @@ -1902,7 +1902,9 @@ jerry_set_prototype (const jerry_value_t obj_val, /**< object value */ } /* jerry_set_prototype */ /** - * Get native handle, associated with specified object + * Get native handle, associated with specified object. + * + * Note: This API is deprecated, please use jerry_get_object_native_pointer instaed. * * @return true - if there is an associated handle (handle is returned through out_handle_p), * false - otherwise @@ -1913,22 +1915,53 @@ jerry_get_object_native_handle (const jerry_value_t obj_val, /**< object to get { jerry_assert_api_available (); - uintptr_t handle_value; + ecma_native_handle_package_t *package_p; - bool does_exist = ecma_get_external_pointer_value (ecma_get_object_from_value (obj_val), - LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE, - &handle_value); + bool does_exist = ecma_get_native_package_value (ecma_get_object_from_value (obj_val), + LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE, + (void **) &package_p); if (does_exist) { - *out_handle_p = handle_value; + *out_handle_p = package_p->handle_p; } return does_exist; } /* jerry_get_object_native_handle */ /** - * Set native handle and an optional free callback for the specified object + * Get native pointer and its type information, associated with specified object. + * + * @return true - if there is an associated pointer (pointer is returned through out_handle_p), + * false - otherwise + */ +bool +jerry_get_object_native_pointer (const jerry_value_t obj_val, /**< object to get native pointer from */ + void **out_native_p, /**< [out] native pointer */ + const jerry_object_native_info_t **out_info_p) /**< [out] the type info + * of the native pointer */ +{ + jerry_assert_api_available (); + + ecma_native_pointer_package_t *package_p; + + bool does_exist = ecma_get_native_package_value (ecma_get_object_from_value (obj_val), + LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, + (void **) &package_p); + + if (does_exist) + { + *out_native_p = (void *) package_p->native_p; + *out_info_p = (const jerry_object_native_info_t *) package_p->info_p; + } + + return does_exist; +} /* jerry_get_object_native_pointer */ + +/** + * Set native handle and an optional free callback for the specified object. + * + * Note: This API is deprecated, please use jerry_set_object_native_pointer instaed. * * Note: * If native handle was already set for the object, its value is updated. @@ -1948,15 +1981,40 @@ jerry_set_object_native_handle (const jerry_value_t obj_val, /**< object to set ecma_object_t *object_p = ecma_get_object_from_value (obj_val); - ecma_create_external_pointer_property (object_p, - LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE, - handle_p); - - ecma_create_external_pointer_property (object_p, - LIT_INTERNAL_MAGIC_STRING_FREE_CALLBACK, - (uintptr_t) freecb_p); + ecma_create_native_handle_property (object_p, + handle_p, + (ecma_external_pointer_t) freecb_p); } /* jerry_set_object_native_handle */ +/** + * Set native pointer and an optional type info for the specified object. + * + * + * Note: + * If native pointer was already set for the object, its value is updated. + * + * Note: + * If a non-NULL free callback is specified in the native type info, + * it will be called by the garbage collector when the object is freed. + * The type info is always overwrites the previous value, so passing + * a NULL value deletes the current type info. + */ +void +jerry_set_object_native_pointer (const jerry_value_t obj_val, /**< object to set native pointer in */ + void *native_p, /**< native pointer */ + const jerry_object_native_info_t *info_p) /**< object's native type info */ +{ + jerry_assert_api_available (); + + ecma_object_t *object_p = ecma_get_object_from_value (obj_val); + + ecma_create_native_pointer_property (object_p, + (ecma_external_pointer_t) native_p, + (ecma_external_pointer_t) info_p); +} /* jerry_set_object_native_pointer */ + + + /** * Applies the given function to the every property in the object. * diff --git a/jerry-core/jerryscript.h b/jerry-core/jerryscript.h index 99b1559fd..266e71977 100644 --- a/jerry-core/jerryscript.h +++ b/jerry-core/jerryscript.h @@ -25,6 +25,12 @@ extern "C" { #endif /* __cplusplus */ +#ifdef __GNUC__ +#define JERRY_DEPRECATED_API __attribute__((deprecated)) +#else /* !__GNUC__ */ +/* TODO: for other compilers */ +#define JERRY_DEPRECATED_API +#endif /* __GNUC__ */ /** \addtogroup jerry Jerry engine interface * @{ */ @@ -156,16 +162,28 @@ typedef jerry_value_t (*jerry_external_handler_t) (const jerry_value_t function_ const jerry_length_t args_count); /** - * Native free callback of an object + * Native free callback of an object (deprecated) */ typedef void (*jerry_object_free_callback_t) (const uintptr_t native_p); +/** + * Native free callback of an object + */ +typedef void (*jerry_object_native_free_callback_t) (void *native_p); + /** * Function type applied for each data property of an object */ typedef bool (*jerry_object_property_foreach_t) (const jerry_value_t property_name, const jerry_value_t property_value, void *user_data_p); +/** + * Type information of a native pointer. + */ +typedef struct +{ + jerry_object_native_free_callback_t free_cb; /**< the free callback of the native pointer */ +} jerry_object_native_info_t; /** * General engine functions @@ -322,9 +340,19 @@ jerry_value_t jerry_get_object_keys (const jerry_value_t obj_val); jerry_value_t jerry_get_prototype (const jerry_value_t obj_val); jerry_value_t jerry_set_prototype (const jerry_value_t obj_val, const jerry_value_t proto_obj_val); +JERRY_DEPRECATED_API bool jerry_get_object_native_handle (const jerry_value_t obj_val, uintptr_t *out_handle_p); +JERRY_DEPRECATED_API void jerry_set_object_native_handle (const jerry_value_t obj_val, uintptr_t handle_p, jerry_object_free_callback_t freecb_p); + +bool jerry_get_object_native_pointer (const jerry_value_t obj_val, + void **out_native_p, + const jerry_object_native_info_t **out_info_p); +void jerry_set_object_native_pointer (const jerry_value_t obj_val, + void *native_p, + const jerry_object_native_info_t *info_p); + bool jerry_foreach_object_property (const jerry_value_t obj_val, jerry_object_property_foreach_t foreach_p, void *user_data_p); diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h index 156be0876..6b5ea17cf 100644 --- a/jerry-core/lit/lit-magic-strings.h +++ b/jerry-core/lit/lit-magic-strings.h @@ -36,10 +36,9 @@ typedef enum #undef LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE LIT_NON_INTERNAL_MAGIC_STRING__COUNT, /**< number of non-internal magic strings */ - LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE = LIT_NON_INTERNAL_MAGIC_STRING__COUNT, /**< native handle associated - * with an object */ - LIT_INTERNAL_MAGIC_STRING_FREE_CALLBACK, /**< object's native free callback */ - + LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE = LIT_NON_INTERNAL_MAGIC_STRING__COUNT, /**< native handle package + * associated with an object */ + LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< native pointer package associated with an object */ LIT_MAGIC_STRING__COUNT /**< number of magic strings */ } lit_magic_string_id_t; diff --git a/tests/unit/test-api.c b/tests/unit/test-api.c index 314ff55e7..18eec9e32 100644 --- a/tests/unit/test-api.c +++ b/tests/unit/test-api.c @@ -107,14 +107,32 @@ handler_throw_test (const jerry_value_t func_obj_val, /**< function object */ } /* handler_throw_test */ static void -handler_construct_freecb (uintptr_t native_p) +handler_construct_freecb (void *native_p) { - TEST_ASSERT (native_p == (uintptr_t) 0x0012345678abcdefull); + TEST_ASSERT ((uintptr_t) native_p == (uintptr_t) 0x0012345678abcdefull); printf ("ok object free callback\n"); test_api_is_free_callback_was_called = true; } /* handler_construct_freecb */ + +/** + * The name of the jerry_object_native_info_t struct. + */ +#define JERRY_NATIVE_HANDLE_INFO_FOR_CTYPE(c_type) _jerry_object_native_info_##c_type + +/** + * Define a native pointer's type based on the C type and free callback. + */ +#define JERRY_DEFINE_NATIVE_HANDLE_INFO(c_type, native_free_cb) \ + static const jerry_object_native_info_t JERRY_NATIVE_HANDLE_INFO_FOR_CTYPE (c_type) = \ + { \ + .free_cb = (jerry_object_native_free_callback_t) native_free_cb \ + } + +JERRY_DEFINE_NATIVE_HANDLE_INFO (bind1, handler_construct_freecb); +JERRY_DEFINE_NATIVE_HANDLE_INFO (bind2, handler_construct_freecb); + static jerry_value_t handler_construct (const jerry_value_t func_obj_val, /**< function object */ const jerry_value_t this_val, /**< this value */ @@ -134,18 +152,20 @@ handler_construct (const jerry_value_t func_obj_val, /**< function object */ jerry_set_property (this_val, field_name, args_p[0]); jerry_release_value (field_name); - jerry_set_object_native_handle (this_val, - (uintptr_t) 0x0000000000000000ull, - handler_construct_freecb); - - uintptr_t ptr = (uintptr_t) NULL; - bool is_ok = jerry_get_object_native_handle (this_val, &ptr); - TEST_ASSERT (is_ok && ptr == (uintptr_t) 0x0000000000000000ull); + jerry_set_object_native_pointer (this_val, + (void *) 0x0000000000000000ull, + &JERRY_NATIVE_HANDLE_INFO_FOR_CTYPE (bind1)); + void *ptr = NULL; + const jerry_object_native_info_t *out_info_p; + bool is_ok = jerry_get_object_native_pointer (this_val, &ptr, &out_info_p); + TEST_ASSERT (is_ok + && (uintptr_t) ptr == (uintptr_t) 0x0000000000000000ull + && out_info_p == &JERRY_NATIVE_HANDLE_INFO_FOR_CTYPE (bind1)); /* check if setting handle for second time is handled correctly */ - jerry_set_object_native_handle (this_val, - (uintptr_t) 0x0012345678abcdefull, - handler_construct_freecb); + jerry_set_object_native_pointer (this_val, + (void *) 0x0012345678abcdefull, + &JERRY_NATIVE_HANDLE_INFO_FOR_CTYPE (bind2)); return jerry_create_boolean (true); } /* handler_construct */ @@ -734,10 +754,12 @@ main (void) jerry_release_value (val_value_field); jerry_release_value (external_construct_val); - uintptr_t ptr = (uintptr_t) NULL; - is_ok = jerry_get_object_native_handle (res, &ptr); + void *ptr = NULL; + const jerry_object_native_info_t *out_info_p; + is_ok = jerry_get_object_native_pointer (res, &ptr, &out_info_p); TEST_ASSERT (is_ok - && ptr == (uintptr_t) 0x0012345678abcdefull); + && (uintptr_t) ptr == (uintptr_t) 0x0012345678abcdefull + && out_info_p == &JERRY_NATIVE_HANDLE_INFO_FOR_CTYPE (bind2)); jerry_release_value (res);