diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 392df8308..680823906 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -225,8 +225,10 @@ typedef bool (*jerry_object_property_foreach_t) (const jerry_value_t property_na **Summary** -Initializes the JerryScript engine, making possible to run JavaScript code and perform operations on -JavaScript values. +Initializes the JerryScript engine, making it possible to run JavaScript code and perform operations +on JavaScript values. See also [jerry_init_with_user_context](#jerry_init_with_user_context) if you +wish to initialize the JerryScript engine in such a way that its context contains a custom pointer +which you can later retrieve using [jerry_get_user_context](#jerry_get_user_context). **Prototype** @@ -259,13 +261,91 @@ jerry_init (jerry_init_flag_t flags) **See also** - [jerry_cleanup](#jerry_cleanup) +- [jerry_init_with_user_context](#jerry_init_with_user_context) + + +## jerry_init_with_user_context + +**Summary** + +Calls [jerry_init](#jerry_init) to initialize the JerryScript engine, thereby making it possible +to run JavaScript code and perform operations on JavaScript values. In addition to the first +parameter this function accepts two more parameters with which it allows the caller to store a +`void *` pointer inside the context being initialized with `jerry_init ()`. The function calls the +callback given in its `init_cb` parameter to allocate the memory for the pointer and it stores the +function pointer given in the `deinit_cb` parameter along with the pointer so that it may be called +to free the stored pointer when `jerry_cleanup ()` is later called to dispose of the context. + +**Prototype** + +```c +void +jerry_init_with_user_context (jerry_init_flag_t flags, + jerry_user_context_init_cb init_cb, + jerry_user_context_deinit_cb deinit_cb); +``` + +`flags` - combination of various engine configuration flags: + +- `JERRY_INIT_EMPTY` - no flags, just initialize in default configuration. +- `JERRY_INIT_SHOW_OPCODES` - print compiled byte-code. +- `JERRY_INIT_SHOW_REGEXP_OPCODES` - print compiled regexp byte-code. +- `JERRY_INIT_MEM_STATS` - dump memory statistics. +- `JERRY_INIT_MEM_STATS_SEPARATE` - dump memory statistics and reset peak values after parse. +- `JERRY_INIT_DEBUGGER` - enable all features required by debugging. + +`init_cb` - a function pointer that will be called to allocate the custom pointer. + +`deinit_cb` - a function pointer that will be called when the custom pointer must be freed. + +**Example** + +```c +void * +init_user_context (void) +{ + void *return_value; + + /* allocate and initialize return_value */ + + return return_value; +} /* init_user_context */ + +void +free_user_context (void *context) +{ + + /* free the value allocated above */ + +} /* free_user_context */ + +{ + /* init_user_context () will be called before the call below returns */ + jerry_init_with_user_context (JERRY_INIT_SHOW_OPCODES | JERRY_INIT_SHOW_REGEXP_OPCODES, + init_user_context, + free_user_context); + + /* ... */ + + /* free_user_context () will be called before the call below returns */ + jerry_cleanup (); +} +``` + +**See also** + +- [jerry_cleanup](#jerry_cleanup) +- [jerry_get_user_context](#jerry_get_user_context) ## jerry_cleanup **Summary** -Finish JavaScript engine execution, freeing memory and JavaScript values. +Finish JavaScript engine execution, freeing memory and JavaScript values. If the context was +initialized with `jerry_init_with_user_context ()` and a `deinit_cb` was provided, then it will +be called to free the memory at the custom pointer which was associated with the context being +cleaned up. *Note*: JavaScript values, received from engine, will be inaccessible after the cleanup. @@ -279,6 +359,37 @@ jerry_cleanup (void); **See also** - [jerry_init](#jerry_init) +- [jerry_init_with_user_context](#jerry_init_with_user_context) + + +## jerry_get_user_context + +**Summary** + +Retrieve the pointer stored within the current context. + +**Prototype** + +```c +void * +jerry_get_user_context (void); +``` + +- return value: the pointer that was assigned during `jerry_init_with_user_context ()` + +**Example** + +```c +{ + /* ... */ + my_context *custom_data = (my_context *) jerry_get_user_context (); + /* ... */ +} +``` + +**See also** +- [jerry_init_with_user_context](#jerry_init_with_user_context) +- [jerry_cleanup](#jerry_cleanup) ## jerry_register_magic_strings diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index fc4c1269c..57d32be43 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -61,6 +61,8 @@ typedef struct ecma_lit_storage_item_t *number_list_first_p; /**< first item of the literal number list */ ecma_object_t *ecma_global_lex_env_p; /**< global lexical environment */ vm_frame_ctx_t *vm_top_context_p; /**< top (current) interpreter context */ + void *user_context_p; /**< user-provided context-specific pointer */ + jerry_user_context_deinit_cb user_context_deinit_cb; /**< user-provided deleter for context-specific pointer */ size_t ecma_gc_objects_number; /**< number of currently allocated objects */ size_t ecma_gc_new_objects; /**< number of newly allocated objects since last GC session */ size_t jmem_heap_allocated_size; /**< size of allocated regions */ diff --git a/jerry-core/jerry.c b/jerry-core/jerry.c index 3bcdfaeea..8b371bb2e 100644 --- a/jerry-core/jerry.c +++ b/jerry-core/jerry.c @@ -166,6 +166,22 @@ jerry_init (jerry_init_flag_t flags) /**< combination of Jerry flags */ #endif /* JERRY_DEBUGGER */ } /* jerry_init */ +/** + * Initialize Jerry engine with custom user context. + */ +void +jerry_init_with_user_context (jerry_init_flag_t flags, /**< combination of Jerry flags */ + jerry_user_context_init_cb init_cb, /**< callback to call to create the user context or + * NULL, in which case no user context will be + * created */ + jerry_user_context_deinit_cb deinit_cb) /**< callback to call to free the user context or + * NULL if it does not need to be freed */ +{ + jerry_init (flags); + JERRY_CONTEXT (user_context_p) = (init_cb ? init_cb () : NULL); + JERRY_CONTEXT (user_context_deinit_cb) = deinit_cb; +} /* jerry_init_with_user_context */ + /** * Terminate Jerry engine */ @@ -185,8 +201,24 @@ jerry_cleanup (void) jmem_finalize (); jerry_make_api_unavailable (); + + if (JERRY_CONTEXT (user_context_deinit_cb)) + { + JERRY_CONTEXT (user_context_deinit_cb) (JERRY_CONTEXT (user_context_p)); + } } /* jerry_cleanup */ +/** + * Retrieve user context. + * + * @return the user-provided context-specific pointer + */ +void * +jerry_get_user_context (void) +{ + return JERRY_CONTEXT (user_context_p); +} /* jerry_get_user_context */ + /** * Register external magic string array */ diff --git a/jerry-core/jerryscript.h b/jerry-core/jerryscript.h index 42ea9e40b..7e724080d 100644 --- a/jerry-core/jerryscript.h +++ b/jerry-core/jerryscript.h @@ -179,6 +179,16 @@ typedef void (*jerry_object_native_free_callback_t) (void *native_p); typedef bool (*jerry_object_property_foreach_t) (const jerry_value_t property_name, const jerry_value_t property_value, void *user_data_p); +/** + * Function type for user context allocation + */ +typedef void *(*jerry_user_context_init_cb) (void); + +/** + * Function type for user context deallocation + */ +typedef void (*jerry_user_context_deinit_cb) (void *user_context_p); + /** * Type information of a native pointer. */ @@ -191,11 +201,15 @@ typedef struct * General engine functions. */ void jerry_init (jerry_init_flag_t flags); +void jerry_init_with_user_context (jerry_init_flag_t flags, + jerry_user_context_init_cb init_cb, + jerry_user_context_deinit_cb deinit_cb); void jerry_cleanup (void); void jerry_register_magic_strings (const jerry_char_ptr_t *ex_str_items_p, uint32_t count, const jerry_length_t *str_lengths_p); void jerry_get_memory_limits (size_t *out_data_bss_brk_limit_p, size_t *out_stack_limit_p); void jerry_gc (void); +void *jerry_get_user_context (void); /** * Parser and executor functions. diff --git a/tests/unit/test-user-context.c b/tests/unit/test-user-context.c new file mode 100644 index 000000000..d2062fbc8 --- /dev/null +++ b/tests/unit/test-user-context.c @@ -0,0 +1,53 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#include "jerryscript.h" +#include "test-common.h" + +static const char *identifying_string = "identifying string"; +static bool user_context_new_was_called = false; +static bool user_context_free_was_called = false; + +static void * +user_context_new (void) +{ + user_context_new_was_called = true; + return (void *) identifying_string; +} /* user_context_new */ + +static void +user_context_free (void *user_context_p) +{ + user_context_free_was_called = true; + TEST_ASSERT (((const char *) user_context_p) == identifying_string); +} /* user_context_free */ + +int +main (void) +{ + TEST_INIT (); + + jerry_init_with_user_context (JERRY_INIT_EMPTY, user_context_new, user_context_free); + + TEST_ASSERT ((((const char *)(jerry_get_user_context ()))) == identifying_string); + + jerry_cleanup (); + + TEST_ASSERT (user_context_new_was_called); + TEST_ASSERT (user_context_free_was_called); + + return 0; +} /* main */