Skip to content

Commit dc065fe

Browse files
committed
Allow the JS objects to have more than one native pointer data
Currently JS objects can only have one native pointer data which could be a limitation in special cases. This patch allows to register multiple native infos, which can be accessed/associated with the corresponding `jerry_object_native_info_t`. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik [email protected]
1 parent 722d092 commit dc065fe

File tree

9 files changed

+379
-96
lines changed

9 files changed

+379
-96
lines changed

docs/02.API-REFERENCE.md

Lines changed: 184 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
47604760
The 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
47804768
bool
47814769
jerry_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

jerry-core/api/jerry.c

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2591,9 +2591,8 @@ jerry_objects_foreach_by_native_info (const jerry_object_native_info_t *native_i
25912591
{
25922592
if (!ecma_is_lexical_environment (iter_p))
25932593
{
2594-
native_pointer_p = ecma_get_native_pointer_value (iter_p);
2594+
native_pointer_p = ecma_get_native_pointer_value (iter_p, (void *) native_info_p);
25952595
if (native_pointer_p
2596-
&& ((const jerry_object_native_info_t *) native_pointer_p->info_p) == native_info_p
25972596
&& !foreach_p (ecma_make_object_value (iter_p), native_pointer_p->data_p, user_data_p))
25982597
{
25992598
return true;
@@ -2605,20 +2604,19 @@ jerry_objects_foreach_by_native_info (const jerry_object_native_info_t *native_i
26052604
} /* jerry_objects_foreach_by_native_info */
26062605

26072606
/**
2608-
* Get native pointer and its type information, associated with specified object.
2607+
* Get native pointer and its type information, associated with the given native type info
26092608
*
26102609
* Note:
2611-
* If native pointer is present, its type information is returned
2612-
* in out_native_pointer_p and out_native_info_p.
2610+
* If native pointer is present, its type information is returned in out_native_pointer_p
26132611
*
26142612
* @return true - if there is an associated pointer,
26152613
* false - otherwise
26162614
*/
26172615
bool
26182616
jerry_get_object_native_pointer (const jerry_value_t obj_val, /**< object to get native pointer from */
26192617
void **out_native_pointer_p, /**< [out] native pointer */
2620-
const jerry_object_native_info_t **out_native_info_p) /**< [out] the type info
2621-
* of the native pointer */
2618+
const jerry_object_native_info_t *native_info_p) /**< the type info
2619+
* of the native pointer */
26222620
{
26232621
jerry_assert_api_available ();
26242622

@@ -2628,7 +2626,7 @@ jerry_get_object_native_pointer (const jerry_value_t obj_val, /**< object to get
26282626
}
26292627

26302628
ecma_native_pointer_t *native_pointer_p;
2631-
native_pointer_p = ecma_get_native_pointer_value (ecma_get_object_from_value (obj_val));
2629+
native_pointer_p = ecma_get_native_pointer_value (ecma_get_object_from_value (obj_val), (void *) native_info_p);
26322630

26332631
if (native_pointer_p == NULL)
26342632
{
@@ -2640,11 +2638,6 @@ jerry_get_object_native_pointer (const jerry_value_t obj_val, /**< object to get
26402638
*out_native_pointer_p = native_pointer_p->data_p;
26412639
}
26422640

2643-
if (out_native_info_p != NULL)
2644-
{
2645-
*out_native_info_p = (const jerry_object_native_info_t *) native_pointer_p->info_p;
2646-
}
2647-
26482641
return true;
26492642
} /* jerry_get_object_native_pointer */
26502643

@@ -2676,6 +2669,35 @@ jerry_set_object_native_pointer (const jerry_value_t obj_val, /**< object to set
26762669
}
26772670
} /* jerry_set_object_native_pointer */
26782671

2672+
/**
2673+
* Delete the previously set native pointer by the native type info from the specified object.
2674+
*
2675+
* Note:
2676+
* If the specified object has no matching native pointer for the given native type info
2677+
* the function has no effect.
2678+
*
2679+
* Note:
2680+
* This operation cannot throw an exception.
2681+
*
2682+
* @return true - if the native pointer has been deleted succesfully
2683+
* false - otherwise
2684+
*/
2685+
bool
2686+
jerry_delete_object_native_pointer (const jerry_value_t obj_val, /**< object to delete native pointer from */
2687+
const jerry_object_native_info_t *native_info_p) /**< object's native type info */
2688+
{
2689+
jerry_assert_api_available ();
2690+
2691+
if (ecma_is_value_object (obj_val))
2692+
{
2693+
ecma_object_t *object_p = ecma_get_object_from_value (obj_val);
2694+
2695+
return ecma_delete_native_pointer_property (object_p, (void *) native_info_p);
2696+
}
2697+
2698+
return false;
2699+
} /* jerry_delete_object_native_pointer */
2700+
26792701
/**
26802702
* Applies the given function to the every property in the object.
26812703
*

0 commit comments

Comments
 (0)