Skip to content

Commit 4404d1f

Browse files
author
Gabriel Schulhof
committed
Add an API to traverse objects by their associated native data
JerryScript-DCO-1.0-Signed-off-by: Gabriel Schulhof [email protected]
1 parent e10f6d6 commit 4404d1f

File tree

4 files changed

+254
-0
lines changed

4 files changed

+254
-0
lines changed

docs/02.API-REFERENCE.md

+120
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,20 @@ typedef bool (*jerry_object_property_foreach_t) (const jerry_value_t property_na
290290
void *user_data_p);
291291
```
292292

293+
## jerry_native_info_foreach_t
294+
295+
**Summary**
296+
297+
Function type applied for each matching object in the engine
298+
299+
**Prototype**
300+
301+
```c
302+
typedef bool (*jerry_native_info_foreach_t) (const jerry_value_t object,
303+
void *object_data_p,
304+
void *user_data_p);
305+
```
306+
293307
## jerry_vm_exec_stop_callback_t
294308

295309
**Summary**
@@ -4564,6 +4578,112 @@ bool foreach_function (const jerry_value_t prop_name,
45644578
- [jerry_object_property_foreach_t](#jerry_object_property_foreach_t)
45654579

45664580

4581+
## jerry_traverse_objects_by_native_info
4582+
4583+
**Summary**
4584+
4585+
Iterate over objects matching a certain native data type.
4586+
4587+
*Note*: Values obtained in `foreach_p` must be retained using [jerry_acquire_value](#jerry_acquire_value).
4588+
4589+
**Prototype**
4590+
4591+
```c
4592+
bool jerry_traverse_objects_by_native_info (const jerry_object_native_info_t *native_info_p,
4593+
jerry_native_info_foreach_t foreach_p,
4594+
void *user_data_p);
4595+
```
4596+
4597+
- `native_info_p` - native pointer's type infomation.
4598+
- return value
4599+
- `true`, if the search function terminated the traversal by returning `false`
4600+
- `false`, if the end of the list of objects was reached
4601+
4602+
**Example**
4603+
4604+
```c
4605+
typedef struct
4606+
{
4607+
int foo;
4608+
bool bar;
4609+
} native_obj_t;
4610+
4611+
typedef struct
4612+
{
4613+
jerry_value_t found_object;
4614+
void *match_data_p;
4615+
} find_object_data_t;
4616+
4617+
static void native_freecb (void *native_p)
4618+
{
4619+
... // free the native pointer
4620+
}
4621+
4622+
// NOTE: The address (!) of type_info acts as a way to uniquely "identify" the
4623+
// C type `native_obj_t *`.
4624+
static const jerry_object_native_info_t native_obj_type_info =
4625+
{
4626+
.free_cb = native_freecb
4627+
};
4628+
4629+
// Function creating JS object that is "backed" by a native_obj_t *:
4630+
{
4631+
...
4632+
4633+
// construct object and native_set value:
4634+
jerry_value_t object = ...;
4635+
native_obj_t *native_obj_p = malloc (sizeof (*native_obj_p));
4636+
jerry_set_object_native_pointer (object, native_obj_p, &native_obj_type_info);
4637+
4638+
...
4639+
}
4640+
4641+
// Native method that retrieves the JavaScript object by way of its native data:
4642+
static bool find_object (const jerry_value_t candidate, void *data_p, void *user_data_p)
4643+
{
4644+
find_object_data_t *find_data_p = (find_object_data_t *) user_data_p;
4645+
4646+
if (find_data_p->match_data_p == data_p)
4647+
{
4648+
// If the object was found, acquire it and store it in the user data.
4649+
find_data_p->found_object = jerry_acquire_value (candidate);
4650+
4651+
// Stop traversing over the objects.
4652+
return false;
4653+
}
4654+
4655+
// Indicate that the object was not found, so traversal must continue.
4656+
return true;
4657+
}
4658+
...
4659+
{
4660+
find_object_data_t find_data =
4661+
{
4662+
.match_data = native_obj
4663+
};
4664+
4665+
if (jerry_traverse_objects_by_native_info (&native_obj_type_info, find_object, &find_data))
4666+
{
4667+
// The object was found and is now stored in find_data.found_object. After using it, it must be released.
4668+
...
4669+
jerry_release_value (find_data.found_object);
4670+
}
4671+
else
4672+
{
4673+
// The object was not found.
4674+
}
4675+
...
4676+
}
4677+
```
4678+
4679+
**See also**
4680+
4681+
- [jerry_create_object](#jerry_create_object)
4682+
- [jerry_set_object_native_pointer](#jerry_set_object_native_pointer)
4683+
- [jerry_get_object_native_pointer](#jerry_get_object_native_pointer)
4684+
- [jerry_object_native_info_t](#jerry_object_native_info_t)
4685+
4686+
45674687
# Input validator functions
45684688

45694689
## jerry_is_valid_utf8_string

jerry-core/api/jerry.c

+39
Original file line numberDiff line numberDiff line change
@@ -2463,6 +2463,45 @@ jerry_set_object_native_handle (const jerry_value_t obj_val, /**< object to set
24632463
}
24642464
} /* jerry_set_object_native_handle */
24652465

2466+
/**
2467+
* Traverse objects having a given native type info.
2468+
*
2469+
* @return true - traversal was interrupted by the callback.
2470+
* false - otherwise - traversal visited all objects.
2471+
*/
2472+
bool
2473+
jerry_traverse_objects_by_native_info (const jerry_object_native_info_t *native_info_p,
2474+
jerry_native_info_foreach_t foreach_p,
2475+
void *user_data_p)
2476+
{
2477+
jerry_assert_api_available ();
2478+
2479+
ecma_object_t *iter_p;
2480+
ecma_native_pointer_t *native_pointer_p;
2481+
2482+
JERRY_ASSERT (native_info_p != NULL);
2483+
JERRY_ASSERT (foreach_p != NULL);
2484+
2485+
for (iter_p = JERRY_CONTEXT (ecma_gc_objects_p);
2486+
iter_p != NULL;
2487+
iter_p = ECMA_GET_POINTER (ecma_object_t, iter_p->gc_next_cp))
2488+
{
2489+
if (!ecma_is_lexical_environment (iter_p))
2490+
{
2491+
native_pointer_p = ecma_get_native_pointer_value (iter_p, LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
2492+
if (native_pointer_p != NULL
2493+
&& ((const jerry_object_native_info_t *) native_pointer_p->u.info_p) == native_info_p
2494+
&& !foreach_p (ecma_make_object_value (iter_p),
2495+
native_pointer_p->data_p,
2496+
user_data_p))
2497+
{
2498+
return true;
2499+
}
2500+
}
2501+
}
2502+
return false;
2503+
} /* jerry_traverse_objects_by_native_info */
2504+
24662505
/**
24672506
* Get native pointer and its type information, associated with specified object.
24682507
*

jerry-core/include/jerryscript-core.h

+10
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,13 @@ typedef bool (*jerry_object_property_foreach_t) (const jerry_value_t property_na
211211
const jerry_value_t property_value,
212212
void *user_data_p);
213213

214+
/**
215+
* Function type applied for each matching object in the engine.
216+
*/
217+
typedef bool (*jerry_native_info_foreach_t) (const jerry_value_t object,
218+
void *object_data_p,
219+
void *user_data_p);
220+
214221
/**
215222
* User context item manager
216223
*/
@@ -439,6 +446,9 @@ void jerry_set_object_native_handle (const jerry_value_t obj_val, uintptr_t hand
439446
bool jerry_get_object_native_pointer (const jerry_value_t obj_val,
440447
void **out_native_pointer_p,
441448
const jerry_object_native_info_t **out_pointer_info_p);
449+
bool jerry_traverse_objects_by_native_info (const jerry_object_native_info_t *native_info_p,
450+
jerry_native_info_foreach_t foreach_p,
451+
void *user_data_p);
442452
void jerry_set_object_native_pointer (const jerry_value_t obj_val,
443453
void *native_pointer_p,
444454
const jerry_object_native_info_t *native_info_p);

tests/unit-core/test-weak-reference.c

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/* Copyright JS Foundation and other contributors, http://js.foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#include "jerryscript.h"
17+
#include "test-common.h"
18+
19+
static int test_data = 1;
20+
21+
static void free_test_data (void *data)
22+
{
23+
TEST_ASSERT ((int *) data == &test_data);
24+
} /* free_test_data */
25+
26+
static const jerry_object_native_info_t test_info =
27+
{
28+
.free_cb = free_test_data
29+
};
30+
31+
static const char *strict_equal_source = "var x = function(a, b) {return a === b;}; x";
32+
33+
static bool
34+
find_test_object (const jerry_value_t candidate,
35+
void *object_data,
36+
void *context)
37+
{
38+
if (object_data == &test_data)
39+
{
40+
*((jerry_value_t *) context) = jerry_acquire_value (candidate);
41+
return false;
42+
}
43+
return true;
44+
} /* find_test_object */
45+
46+
int
47+
main (void)
48+
{
49+
jerry_init (JERRY_INIT_EMPTY);
50+
51+
/* Render strict-equal as a function. */
52+
jerry_value_t parse_result = jerry_parse ((jerry_char_t *) strict_equal_source, strlen (strict_equal_source), true);
53+
TEST_ASSERT (!jerry_value_has_error_flag (parse_result));
54+
jerry_value_t strict_equal = jerry_run (parse_result);
55+
TEST_ASSERT (!jerry_value_has_error_flag (strict_equal));
56+
jerry_release_value (parse_result);
57+
58+
/* Create an object and associate some native data with it. */
59+
jerry_value_t object = jerry_create_object ();
60+
jerry_set_object_native_pointer (object, &test_data, &test_info);
61+
62+
/* Retrieve the object by its native pointer. */
63+
64+
jerry_value_t found_object;
65+
TEST_ASSERT (jerry_traverse_objects_by_native_info (&test_info, find_test_object, &found_object));
66+
jerry_value_t args[2] = {object, found_object};
67+
68+
/* Assert that the correct object was retrieved. */
69+
jerry_value_t undefined = jerry_create_undefined ();
70+
jerry_value_t strict_equal_result = jerry_call_function (strict_equal, undefined, args, 2);
71+
jerry_release_value (undefined);
72+
TEST_ASSERT (jerry_value_is_boolean (strict_equal_result) && jerry_get_boolean_value (strict_equal_result));
73+
jerry_release_value (strict_equal_result);
74+
jerry_release_value (found_object);
75+
jerry_release_value (object);
76+
jerry_release_value (strict_equal);
77+
78+
/* Collect garbage. */
79+
jerry_gc ();
80+
81+
/* Attempt to retrieve the object by its native pointer again. */
82+
TEST_ASSERT (!jerry_traverse_objects_by_native_info (&test_info, find_test_object, &found_object));
83+
84+
jerry_cleanup ();
85+
} /* main */

0 commit comments

Comments
 (0)