Skip to content

Add finalize_cb to jerry_context_data_manager_t #2269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 41 additions & 5 deletions docs/02.API-REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,53 @@ typedef uint32_t jerry_value_t;

Structure that defines how a context data item will be initialized and deinitialized. JerryScript zeroes out the memory
for the item by default, and if the `init_cb` field is not NULL, it will be called with the pointer to the memory as
an additional custom initializer. The `deinit_cb` (if non-`NULL`) is called during a call to `jerry_cleanup()` to run
any custom deinitialization.
an additional custom initializer. The `deinit_cb` (if non-`NULL`) is called during a call to `jerry_cleanup ()` to run
any custom deinitialization *before* the VM has been fully cleaned up. The `finalize_cb` (if non-`NULL`) is also called
during a call to `jerry_cleanup ()` to run any custom deinitialization *after* the VM has been fully cleaned up.

**Prototype**

```c
typedef struct
{
void (*init_cb) (void *); /**< callback responsible for initializing a context item, or NULL */
void (*deinit_cb) (void *); /**< callback responsible for deinitializing a context item, or NULL */
size_t bytes_needed; /**< number of bytes to allocate for this manager */
/**
* Callback responsible for initializing a context item, or NULL to zero out the memory. This is called lazily, the
* first time jerry_get_context_data () is called with this manager.
*
* @param [in] data The buffer that JerryScript allocated for the manager. The buffer is zeroed out. The size is
* determined by the bytes_needed field. The buffer is kept alive until jerry_cleanup () is called.
*/
void (*init_cb) (void *data);

/**
* Callback responsible for deinitializing a context item, or NULL. This is called as part of jerry_cleanup (),
* right *before* the VM has been cleaned up. This is a good place to release strong references to jerry_value_t's
* that the manager may be holding.
* Note: because the VM has not been fully cleaned up yet, jerry_object_native_info_t free_cb's can still get called
* *after* all deinit_cb's have been run. See finalize_cb for a callback that is guaranteed to run *after* all
* free_cb's have been run.
*
* @param [in] data The buffer that JerryScript allocated for the manager.
*/
void (*deinit_cb) (void *data);

/**
* Callback responsible for finalizing a context item, or NULL. This is called as part of jerry_cleanup (),
* right *after* the VM has been cleaned up and destroyed and jerry_... APIs cannot be called any more. At this point,
* all values in the VM have been cleaned up. This is a good place to clean up native state that can only be cleaned
* up at the very end when there are no more VM values around that may need to access that state.
*
* @param [in] data The buffer that JerryScript allocated for the manager. After returning from this callback,
* the data pointer may no longer be used.
*/
void (*finalize_cb) (void *data);

/**
* Number of bytes to allocate for this manager. This is the size of the buffer that JerryScript will allocate on
* behalf of the manager. The pointer to this buffer is passed into init_cb, deinit_cb and finalize_cb. It is also
* returned from the jerry_get_context_data () API.
*/
size_t bytes_needed;
} jerry_context_data_manager_t;
```

Expand Down
21 changes: 16 additions & 5 deletions jerry-core/api/jerry.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,24 +210,35 @@ jerry_cleanup (void)
}
#endif /* JERRY_DEBUGGER */

for (jerry_context_data_header_t *this_p = JERRY_CONTEXT (context_data_p), *next_p = NULL;
for (jerry_context_data_header_t *this_p = JERRY_CONTEXT (context_data_p);
this_p != NULL;
this_p = next_p)
this_p = this_p->next_p)
{
next_p = this_p->next_p;
if (this_p->manager_p->deinit_cb)
{
this_p->manager_p->deinit_cb (JERRY_CONTEXT_DATA_HEADER_USER_DATA (this_p));
}
jmem_heap_free_block (this_p, sizeof (jerry_context_data_header_t) + this_p->manager_p->bytes_needed);
}

#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
ecma_free_all_enqueued_jobs ();
#endif /* CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */
ecma_finalize ();
jmem_finalize ();
jerry_make_api_unavailable ();

for (jerry_context_data_header_t *this_p = JERRY_CONTEXT (context_data_p), *next_p = NULL;
this_p != NULL;
this_p = next_p)
{
next_p = this_p->next_p;
if (this_p->manager_p->finalize_cb)
{
this_p->manager_p->finalize_cb (JERRY_CONTEXT_DATA_HEADER_USER_DATA (this_p));
}
jmem_heap_free_block (this_p, sizeof (jerry_context_data_header_t) + this_p->manager_p->bytes_needed);
}

jmem_finalize ();
} /* jerry_cleanup */

/**
Expand Down
41 changes: 38 additions & 3 deletions jerry-core/include/jerryscript-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,44 @@ typedef bool (*jerry_objects_foreach_by_native_info_t) (const jerry_value_t obje
*/
typedef struct
{
void (*init_cb) (void *); /**< callback responsible for initializing a context item, or NULL to zero out the memory */
void (*deinit_cb) (void *); /**< callback responsible for deinitializing a context item, or NULL */
size_t bytes_needed; /**< number of bytes to allocate for this manager */
/**
* Callback responsible for initializing a context item, or NULL to zero out the memory. This is called lazily, the
* first time jerry_get_context_data () is called with this manager.
*
* @param [in] data The buffer that JerryScript allocated for the manager. The buffer is zeroed out. The size is
* determined by the bytes_needed field. The buffer is kept alive until jerry_cleanup () is called.
*/
void (*init_cb) (void *data);

/**
* Callback responsible for deinitializing a context item, or NULL. This is called as part of jerry_cleanup (),
* right *before* the VM has been cleaned up. This is a good place to release strong references to jerry_value_t's
* that the manager may be holding.
* Note: because the VM has not been fully cleaned up yet, jerry_object_native_info_t free_cb's can still get called
* *after* all deinit_cb's have been run. See finalize_cb for a callback that is guaranteed to run *after* all
* free_cb's have been run.
*
* @param [in] data The buffer that JerryScript allocated for the manager.
*/
void (*deinit_cb) (void *data);

/**
* Callback responsible for finalizing a context item, or NULL. This is called as part of jerry_cleanup (),
* right *after* the VM has been cleaned up and destroyed and jerry_... APIs cannot be called any more. At this point,
* all values in the VM have been cleaned up. This is a good place to clean up native state that can only be cleaned
* up at the very end when there are no more VM values around that may need to access that state.
*
* @param [in] data The buffer that JerryScript allocated for the manager. After returning from this callback,
* the data pointer may no longer be used.
*/
void (*finalize_cb) (void *data);

/**
* Number of bytes to allocate for this manager. This is the size of the buffer that JerryScript will allocate on
* behalf of the manager. The pointer to this buffer is passed into init_cb, deinit_cb and finalize_cb. It is also
* returned from the jerry_get_context_data () API.
*/
size_t bytes_needed;
} jerry_context_data_manager_t;

/**
Expand Down
15 changes: 14 additions & 1 deletion tests/unit-core/test-context-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@

static bool test_context_data1_new_called = false;
static bool test_context_data2_new_called = false;
static bool test_context_data3_new_called = false;
static bool test_context_data1_free_called = false;
static bool test_context_data2_free_called = false;
static bool test_context_data3_new_called = false;
static bool test_context_data1_finalize_called = false;

/* Context item 1 */
const char *string1 = "item1";
Expand All @@ -38,12 +39,23 @@ test_context_data1_free (void *user_data_p)
{
test_context_data1_free_called = true;
TEST_ASSERT ((*(const char **) user_data_p) == string1);
TEST_ASSERT (!test_context_data1_finalize_called);
} /* test_context_data1_free */

static void
test_context_data1_finalize (void *user_data_p)
{
TEST_ASSERT (test_context_data1_free_called);
TEST_ASSERT (!test_context_data1_finalize_called);
TEST_ASSERT ((*(const char **) user_data_p) == string1);
test_context_data1_finalize_called = true;
} /* test_context_data1_finalize */

static const jerry_context_data_manager_t manager1 =
{
.init_cb = test_context_data1_new,
.deinit_cb = test_context_data1_free,
.finalize_cb = test_context_data1_finalize,
.bytes_needed = sizeof (const char *)
};

Expand Down Expand Up @@ -86,6 +98,7 @@ static const jerry_context_data_manager_t manager3 =
.init_cb = test_context_data3_new,
/* NULL is allowed: */
.deinit_cb = NULL,
.finalize_cb = NULL,
.bytes_needed = 0,
};

Expand Down