@@ -4756,97 +4756,197 @@ jerry_set_prototype (const jerry_value_t obj_val,
47564756
47574757**Summary**
47584758
4759- Get native pointer and its type information.
4759+ Get native pointer by the given type information.
47604760The pointer and the type information are previously associated with the object by jerry_set_object_native_pointer.
47614761
4762- *Note*: It is recommended to ensure that the `out_native_info_p` value pointer
4763- is equal to the native info pointer that is expected, before casting
4764- and accessing the `out_native_pointer_p`.
4765- An example of when this is important: external functions that expect
4766- `this` to have a native pointer of a certain C type.
4767- It is possible in JavaScript to change `this` at will – using `call()`,
4768- `apply()` or `bind()`. Therefore, it is possible that the native pointer
4769- of `this` is not of the expected C type. To handle this safely and
4770- securely, one must always add type checks to make sure that the
4771- `out_native_pointer_p` is of the expected type, before casting
4772- and dereferencing `out_native_pointer_p`.
4773-
4774- *Note*: `out_native_pointer_p` and `out_native_info_p` can be NULL, and it means the
4775- caller doesn't want to get the native_pointer or type information.
4762+ *Note*: `out_native_pointer_p` can be NULL, and it means the
4763+ caller doesn't want to get the native_pointer.
47764764
47774765**Prototype**
47784766
47794767```c
47804768bool
47814769jerry_get_object_native_pointer (const jerry_value_t obj_val,
47824770 void **out_native_pointer_p,
4783- const jerry_object_native_info_t **out_native_info_p )
4771+ const jerry_object_native_info_t *native_info_p )
47844772```
47854773
47864774- `obj_val` - object value to get native pointer from.
47874775- `out_native_pointer_p` - native pointer (output parameter).
4788- - `out_native_info_p ` - native pointer's type information (output parameter) .
4776+ - `native_info_p ` - native pointer's type information.
47894777- return value
4790- - true, if there is native pointer associated with the object
4778+ - true, if there is native pointer associated of the specified object with the given native type info
47914779 - false, otherwise
47924780
47934781**Example**
47944782
4783+ [doctest]: # ()
4784+
47954785```c
4796- typedef struct {
4797- int foo;
4798- bool bar;
4799- } native_obj_t;
4786+ #include <stdio.h>
4787+ #include <stdlib.h>
4788+ #include <string.h>
4789+ #include "jerryscript.h"
48004790
4801- static void native_freecb (void *native_p)
4791+ typedef struct
48024792{
4803- ... // free the native pointer
4793+ char *data_p;
4794+ unsigned int length;
4795+ } buffer_native_object_t;
4796+
4797+ typedef struct
4798+ {
4799+ int area;
4800+ int perimeter;
4801+ } shape_native_object_t;
4802+
4803+ #define SECRET_INFO ((void *) 42)
4804+
4805+ static void
4806+ buffer_native_freecb (void *native_p)
4807+ {
4808+ char *data_p = ((buffer_native_object_t*)native_p)->data_p;
4809+
4810+ if (data_p != NULL)
4811+ {
4812+ free (data_p);
4813+ }
4814+
4815+ free (native_p);
4816+ }
4817+
4818+ static void
4819+ shape_native_freecb (void *native_p)
4820+ {
4821+ free (native_p);
4822+ }
4823+
4824+ static void
4825+ destructor_freecb (void *native_p)
4826+ {
4827+ printf("Note: the object has been freed\n");
48044828}
48054829
48064830// NOTE: The address (!) of type_info acts as a way to uniquely "identify" the
4807- // C type `native_obj_t *`.
4808- static const jerry_object_native_info_t native_obj_type_info =
4831+ // C type `buffer_native_object_t *`.
4832+ static const jerry_object_native_info_t buffer_obj_type_info =
48094833{
4810- .free_cb = native_freecb
4834+ .free_cb = buffer_native_freecb
48114835};
48124836
4813- // Function creating JS object that is "backed" by a native_obj_t *:
4837+ // NOTE: The address (!) of type_info acts as a way to uniquely "identify" the
4838+ // C type `shape_native_object_t *`.
4839+ static const jerry_object_native_info_t shape_obj_type_info =
48144840{
4815- ...
4841+ .free_cb = shape_native_freecb
4842+ };
48164843
4817- // construct object and native_set value:
4818- jerry_value_t object = ...;
4819- native_obj_t *native_obj = malloc(sizeof(*native_obj));
4820- jerry_set_object_native_pointer (object, native_obj, &native_obj_type_info);
4844+ // NOTE: The address (!) of type_info is the unique "identifier"
4845+ static const jerry_object_native_info_t destructor_obj_type_info =
4846+ {
4847+ .free_cb = destructor_freecb
4848+ };
48214849
4822- ...
4850+ static void
4851+ print_buffer (char *data_p,
4852+ unsigned int length)
4853+ {
4854+ for (unsigned int i = 0; i < length; ++i)
4855+ {
4856+ printf("%c", data_p[i]);
4857+ }
4858+
4859+ printf("\n");
48234860}
48244861
4825- // Native method, `this` is expected to be "backed" by a native_obj_t *:
4862+ static void
4863+ do_stuff (jerry_value_t object)
48264864{
48274865 void *native_p;
4828- const jerry_object_native_info_t *type_p;
4829- bool has_p = jerry_get_object_native_pointer (this_val, &native_p, &type_p);
4866+ bool has_p = jerry_get_object_native_pointer (object, &native_p, &buffer_obj_type_info);
48304867
4831- if (has_p)
4868+ if (! has_p)
48324869 {
4833- // The type_p pointer address itself is used to identify the type:
4834- if (type_p == &native_obj_type_info)
4870+ // Process the error
4871+ return;
4872+ }
4873+
4874+ // It is safe to cast to buffer_native_object_t * and dereference the pointer:
4875+ buffer_native_object_t *buffer_p = (buffer_native_object_t *) native_p;
4876+ print_buffer (buffer_p->data_p, buffer_p->length); // Usage of buffer_p
4877+
4878+ bool need_shape_info = true; // implementation dependent
4879+
4880+ if (need_shape_info)
4881+ {
4882+ has_p = jerry_get_object_native_pointer (object, &native_p, &shape_obj_type_info);
4883+
4884+ if (!has_p)
48354885 {
4836- // The type of this's native pointer matches what is expected.
4837- // Only now is it safe to cast to native_obj_t * and dereference the
4838- // pointer:
4839- native_obj_t *native_obj = native_p;
4840- native_obj->bar = ...; // Safe to access now!
4886+ // Process the error
4887+ return;
48414888 }
4842- else
4889+
4890+ // It is safe to cast to shape_native_object_t * and dereference the pointer:
4891+ shape_native_object_t *shape_p = (shape_native_object_t *) native_p;
4892+
4893+ printf("Area: %d\tPerimeter: %d\n", shape_p->area, shape_p->perimeter); // Usage of shape_p
4894+ }
4895+
4896+ bool need_secret_info = true; // implementation dependent
4897+
4898+ if (need_secret_info)
4899+ {
4900+ has_p = jerry_get_object_native_pointer (object, &native_p, NULL);
4901+
4902+ if (!has_p)
48434903 {
4844- // The type of this's native pointer is NOT what we expected!
4845- // We should not cast to native_obj_t * and dereference because it's unsafe.
4846- // Handle the error here, for example throw an error.
4904+ // Process the error
4905+ return;
4906+ }
4907+
4908+ printf("Secret: %d\n", (int)((uintptr_t) native_p)); // Usage of native_p
4909+
4910+ bool deleted = jerry_delete_object_native_pointer (object, NULL);
4911+
4912+ if (deleted)
4913+ {
4914+ printf("The secret is no longer available\n");
48474915 }
48484916 }
4849- ...
4917+ }
4918+
4919+ int
4920+ main (void)
4921+ {
4922+ jerry_init (JERRY_INIT_EMPTY);
4923+
4924+ jerry_value_t object = jerry_create_object ();
4925+ buffer_native_object_t *buffer_p = (buffer_native_object_t *) malloc (sizeof (buffer_native_object_t));
4926+ buffer_p->length = 14;
4927+ buffer_p->data_p = (char *) malloc (buffer_p->length * sizeof (char));
4928+ memcpy (buffer_p->data_p, "My buffer data", buffer_p->length);
4929+ jerry_set_object_native_pointer (object, buffer_p, &buffer_obj_type_info);
4930+
4931+ shape_native_object_t *shape_p = (shape_native_object_t *) malloc (sizeof (shape_native_object_t));
4932+ shape_p->area = 6;
4933+ shape_p->perimeter = 12;
4934+ jerry_set_object_native_pointer (object, shape_p, &shape_obj_type_info);
4935+
4936+ // The native pointer can be NULL. This gives possibily to get notified via the native type info's
4937+ // free callback when the object has been freed by the GC.
4938+ jerry_set_object_native_pointer (object, NULL, &destructor_obj_type_info);
4939+
4940+ // The native type info can be NULL as well. In this case the registered property is simply freed
4941+ // when the object is freed by te GC.
4942+ jerry_set_object_native_pointer (object, SECRET_INFO, NULL);
4943+
4944+ do_stuff (object);
4945+
4946+ jerry_release_value (object);
4947+ jerry_cleanup ();
4948+
4949+ return 0;
48504950}
48514951```
48524952
@@ -4897,6 +4997,40 @@ best-practice example.
48974997- [jerry_get_object_native_pointer](#jerry_get_object_native_pointer)
48984998- [jerry_object_native_info_t](#jerry_object_native_info_t)
48994999
5000+ ## jerry_delete_object_native_pointer
5001+
5002+ **Summary**
5003+
5004+ Delete the native pointer of the specified object associated with the given native type info.
5005+ You can get them by calling jerry_get_object_native_pointer later.
5006+
5007+ *Note*: If the specified object has no matching native pointer for the given native type info the operation has no effect.
5008+
5009+ *Note*: This operation cannot throw an exception.
5010+
5011+ **Prototype**
5012+
5013+ ```c
5014+ bool
5015+ jerry_delete_object_native_pointer (const jerry_value_t obj_val,
5016+ const jerry_object_native_info_t *info_p)
5017+ ```
5018+
5019+ - `obj_val` - object to delete native pointer from.
5020+ - `info_p` - native pointer's type information.
5021+
5022+ **Example**
5023+
5024+ See [jerry_get_object_native_pointer](#jerry_get_object_native_pointer) for a
5025+ best-practice example.
5026+
5027+ **See also**
5028+
5029+ - [jerry_create_object](#jerry_create_object)
5030+ - [jerry_get_object_native_pointer](#jerry_get_object_native_pointer)
5031+ - [jerry_get_object_native_pointer](#jerry_set_object_native_pointer)
5032+ - [jerry_object_native_info_t](#jerry_object_native_info_t)
5033+
49005034
49015035## jerry_foreach_object_property
49025036
0 commit comments