Skip to content

Commit b3f4aa6

Browse files
rerobikaLaszloLango
authored andcommitted
Allow the JS objects to have more than one native pointer data (#2814)
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 frobert@inf.u-szeged.hu
1 parent c818930 commit b3f4aa6

File tree

14 files changed

+433
-177
lines changed

14 files changed

+433
-177
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);
4867+
4868+
if (!has_p)
4869+
{
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
48304879

4831-
if (has_p)
4880+
if (need_shape_info)
48324881
{
4833-
// The type_p pointer address itself is used to identify the type:
4834-
if (type_p == &native_obj_type_info)
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)
4903+
{
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)
48434913
{
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.
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*:
5008+
- If the specified object has no matching native pointer for the given native type info the operation has no effect.
5009+
- 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)