Last active
December 12, 2018 12:38
-
-
Save xeioex/b504bcadc8a9ba651155d7513c82710e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1544527173 -10800 | |
| # Tue Dec 11 14:19:33 2018 +0300 | |
| # Node ID 14801762b1eb5199453acc3c774b98ace7f9abb5 | |
| # Parent 0709c3d38212df011229fccb2e7a9e7f23263cce | |
| Added setImmediate(). | |
| This closes #66 issue on Github. | |
| diff --git a/njs/njs.c b/njs/njs.c | |
| --- a/njs/njs.c | |
| +++ b/njs/njs.c | |
| @@ -501,7 +501,7 @@ njs_vm_call(njs_vm_t *vm, njs_function_t | |
| njs_vm_event_t | |
| njs_vm_add_event(njs_vm_t *vm, njs_function_t *function, nxt_uint_t once, | |
| - njs_host_event_t host_ev, njs_event_destructor destructor) | |
| + njs_host_event_t host_ev, njs_event_destructor_t destructor) | |
| { | |
| njs_event_t *event; | |
| diff --git a/njs/njs.h b/njs/njs.h | |
| --- a/njs/njs.h | |
| +++ b/njs/njs.h | |
| @@ -125,15 +125,15 @@ typedef void * njs_ | |
| typedef void * njs_host_event_t; | |
| typedef void * njs_external_ptr_t; | |
| -typedef njs_host_event_t (*njs_set_timer)(njs_external_ptr_t external, | |
| +typedef njs_host_event_t (*njs_set_timer_t)(njs_external_ptr_t external, | |
| uint64_t delay, njs_vm_event_t vm_event); | |
| -typedef void (*njs_event_destructor)(njs_external_ptr_t external, | |
| +typedef void (*njs_event_destructor_t)(njs_external_ptr_t external, | |
| njs_host_event_t event); | |
| typedef struct { | |
| - njs_set_timer set_timer; | |
| - njs_event_destructor clear_timer; | |
| + njs_set_timer_t set_timer; | |
| + njs_event_destructor_t clear_timer; | |
| } njs_vm_ops_t; | |
| @@ -167,7 +167,7 @@ NXT_EXPORT nxt_int_t njs_vm_call(njs_vm_ | |
| NXT_EXPORT njs_vm_event_t njs_vm_add_event(njs_vm_t *vm, | |
| njs_function_t *function, nxt_uint_t once, njs_host_event_t host_ev, | |
| - njs_event_destructor destructor); | |
| + njs_event_destructor_t destructor); | |
| NXT_EXPORT void njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event); | |
| NXT_EXPORT nxt_int_t njs_vm_pending(njs_vm_t *vm); | |
| NXT_EXPORT nxt_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, | |
| diff --git a/njs/njs_builtin.c b/njs/njs_builtin.c | |
| --- a/njs/njs_builtin.c | |
| +++ b/njs/njs_builtin.c | |
| @@ -111,6 +111,7 @@ const njs_object_init_t *njs_function | |
| &njs_decode_uri_component_function_init, | |
| &njs_require_function_init, | |
| &njs_set_timeout_function_init, | |
| + &njs_set_immediate_function_init, | |
| &njs_clear_timeout_function_init, | |
| NULL | |
| }; | |
| @@ -132,6 +133,8 @@ const njs_function_init_t njs_native_fu | |
| { njs_module_require, { NJS_SKIP_ARG, NJS_STRING_ARG } }, | |
| { njs_set_timeout, | |
| { NJS_SKIP_ARG, NJS_FUNCTION_ARG, NJS_NUMBER_ARG } }, | |
| + { njs_set_immediate, | |
| + { NJS_SKIP_ARG, NJS_FUNCTION_ARG } }, | |
| { njs_clear_timeout, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, | |
| }; | |
| diff --git a/njs/njs_event.h b/njs/njs_event.h | |
| --- a/njs/njs_event.h | |
| +++ b/njs/njs_event.h | |
| @@ -16,17 +16,17 @@ | |
| typedef struct { | |
| - njs_function_t *function; | |
| - njs_value_t *args; | |
| - nxt_uint_t nargs; | |
| - njs_host_event_t host_event; | |
| - njs_event_destructor destructor; | |
| + njs_function_t *function; | |
| + njs_value_t *args; | |
| + nxt_uint_t nargs; | |
| + njs_host_event_t host_event; | |
| + njs_event_destructor_t destructor; | |
| - njs_value_t id; | |
| - nxt_queue_link_t link; | |
| + njs_value_t id; | |
| + nxt_queue_link_t link; | |
| - unsigned posted:1; | |
| - unsigned once:1; | |
| + unsigned posted:1; | |
| + unsigned once:1; | |
| } njs_event_t; | |
| diff --git a/njs/njs_generator.c b/njs/njs_generator.c | |
| --- a/njs/njs_generator.c | |
| +++ b/njs/njs_generator.c | |
| @@ -387,6 +387,7 @@ njs_generator(njs_vm_t *vm, njs_generato | |
| case NJS_TOKEN_DECODE_URI_COMPONENT: | |
| case NJS_TOKEN_REQUIRE: | |
| case NJS_TOKEN_SET_TIMEOUT: | |
| + case NJS_TOKEN_SET_IMMEDIATE: | |
| case NJS_TOKEN_CLEAR_TIMEOUT: | |
| return njs_generate_builtin_object(vm, generator, node); | |
| diff --git a/njs/njs_lexer_keyword.c b/njs/njs_lexer_keyword.c | |
| --- a/njs/njs_lexer_keyword.c | |
| +++ b/njs/njs_lexer_keyword.c | |
| @@ -90,6 +90,7 @@ static const njs_keyword_t njs_keywords | |
| { nxt_string("decodeURIComponent"), NJS_TOKEN_DECODE_URI_COMPONENT, 0 }, | |
| { nxt_string("require"), NJS_TOKEN_REQUIRE, 0 }, | |
| { nxt_string("setTimeout"), NJS_TOKEN_SET_TIMEOUT, 0 }, | |
| + { nxt_string("setImmediate"), NJS_TOKEN_SET_IMMEDIATE, 0 }, | |
| { nxt_string("clearTimeout"), NJS_TOKEN_CLEAR_TIMEOUT, 0 }, | |
| /* Reserved words. */ | |
| diff --git a/njs/njs_parser.c b/njs/njs_parser.c | |
| --- a/njs/njs_parser.c | |
| +++ b/njs/njs_parser.c | |
| @@ -2045,6 +2045,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa | |
| case NJS_TOKEN_DECODE_URI_COMPONENT: | |
| case NJS_TOKEN_REQUIRE: | |
| case NJS_TOKEN_SET_TIMEOUT: | |
| + case NJS_TOKEN_SET_IMMEDIATE: | |
| case NJS_TOKEN_CLEAR_TIMEOUT: | |
| return njs_parser_builtin_function(vm, parser, node); | |
| diff --git a/njs/njs_parser.h b/njs/njs_parser.h | |
| --- a/njs/njs_parser.h | |
| +++ b/njs/njs_parser.h | |
| @@ -198,6 +198,7 @@ typedef enum { | |
| NJS_TOKEN_DECODE_URI_COMPONENT, | |
| NJS_TOKEN_REQUIRE, | |
| NJS_TOKEN_SET_TIMEOUT, | |
| + NJS_TOKEN_SET_IMMEDIATE, | |
| NJS_TOKEN_CLEAR_TIMEOUT, | |
| NJS_TOKEN_RESERVED, | |
| diff --git a/njs/njs_time.c b/njs/njs_time.c | |
| --- a/njs/njs_time.c | |
| +++ b/njs/njs_time.c | |
| @@ -10,10 +10,11 @@ | |
| #include <stdio.h> | |
| -njs_ret_t | |
| -njs_set_timeout(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| - njs_index_t unused) | |
| +static njs_ret_t | |
| +njs_set_timer(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| + njs_index_t unused, nxt_bool_t immediate) | |
| { | |
| + nxt_uint_t n; | |
| uint64_t delay; | |
| njs_event_t *event; | |
| njs_vm_ops_t *ops; | |
| @@ -36,7 +37,7 @@ njs_set_timeout(njs_vm_t *vm, njs_value_ | |
| delay = 0; | |
| - if (nargs >= 3 && njs_is_number(&args[2])) { | |
| + if (!immediate && nargs >= 3 && njs_is_number(&args[2])) { | |
| delay = args[2].data.u.number; | |
| } | |
| @@ -45,9 +46,11 @@ njs_set_timeout(njs_vm_t *vm, njs_value_ | |
| goto memory_error; | |
| } | |
| - event->destructor = ops->clear_timer; | |
| + n = immediate ? 2 : 3; | |
| + | |
| + event->destructor = (ops != NULL) ? ops->clear_timer : NULL; | |
| event->function = args[1].data.u.function; | |
| - event->nargs = (nargs >= 3) ? nargs - 3 : 0; | |
| + event->nargs = (nargs >= n) ? nargs - n : 0; | |
| event->once = 1; | |
| event->posted = 0; | |
| @@ -58,11 +61,11 @@ njs_set_timeout(njs_vm_t *vm, njs_value_ | |
| goto memory_error; | |
| } | |
| - memcpy(event->args, &args[3], sizeof(njs_value_t) * event->nargs); | |
| + memcpy(event->args, &args[n], sizeof(njs_value_t) * event->nargs); | |
| } | |
| event->host_event = ops->set_timer(vm->external, delay, event); | |
| - if (event->host_event == NULL) { | |
| + if (nxt_slow_path(event->host_event == NULL)) { | |
| njs_internal_error(vm, "set_timer() failed"); | |
| return NJS_ERROR; | |
| } | |
| @@ -78,6 +81,22 @@ memory_error: | |
| njs_ret_t | |
| +njs_set_timeout(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| + njs_index_t unused) | |
| +{ | |
| + return njs_set_timer(vm, args, nargs, unused, 0); | |
| +} | |
| + | |
| + | |
| +njs_ret_t | |
| +njs_set_immediate(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| + njs_index_t unused) | |
| +{ | |
| + return njs_set_timer(vm, args, nargs, unused, 1); | |
| +} | |
| + | |
| + | |
| +njs_ret_t | |
| njs_clear_timeout(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| njs_index_t unused) | |
| { | |
| @@ -116,6 +135,12 @@ const njs_object_init_t njs_set_timeout | |
| 0, | |
| }; | |
| +const njs_object_init_t njs_set_immediate_function_init = { | |
| + nxt_string("setImmediate"), | |
| + NULL, | |
| + 0, | |
| +}; | |
| + | |
| const njs_object_init_t njs_clear_timeout_function_init = { | |
| nxt_string("clearTimeout"), | |
| diff --git a/njs/njs_time.h b/njs/njs_time.h | |
| --- a/njs/njs_time.h | |
| +++ b/njs/njs_time.h | |
| @@ -10,11 +10,14 @@ | |
| njs_ret_t njs_set_timeout(njs_vm_t *vm, njs_value_t *args, | |
| nxt_uint_t nargs, njs_index_t unused); | |
| +njs_ret_t njs_set_immediate(njs_vm_t *vm, njs_value_t *args, | |
| + nxt_uint_t nargs, njs_index_t unused); | |
| njs_ret_t njs_clear_timeout(njs_vm_t *vm, njs_value_t *args, | |
| nxt_uint_t nargs, njs_index_t unused); | |
| extern const njs_object_init_t njs_set_timeout_function_init; | |
| +extern const njs_object_init_t njs_set_immediate_function_init; | |
| extern const njs_object_init_t njs_clear_timeout_function_init; | |
| #endif /* _NJS_TIMEOUT_H_INCLUDED_ */ | |
| diff --git a/njs/njs_vm.h b/njs/njs_vm.h | |
| --- a/njs/njs_vm.h | |
| +++ b/njs/njs_vm.h | |
| @@ -930,6 +930,7 @@ enum njs_function_e { | |
| NJS_FUNCTION_STRING_DECODE_URI_COMPONENT, | |
| NJS_FUNCTION_REQUIRE, | |
| NJS_FUNCTION_SET_TIMEOUT, | |
| + NJS_FUNCTION_SET_IMMEDIATE, | |
| NJS_FUNCTION_CLEAR_TIMEOUT, | |
| #define NJS_FUNCTION_MAX (NJS_FUNCTION_CLEAR_TIMEOUT + 1) | |
| }; | |
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1544527174 -10800 | |
| # Tue Dec 11 14:19:34 2018 +0300 | |
| # Node ID 141759f986b49a4721c2541b1b836db25bf35621 | |
| # Parent 14801762b1eb5199453acc3c774b98ace7f9abb5 | |
| njs_vm_run() is rectified. | |
| Previously, both njs_vm_call() and njs_vm_run() can be used to run njs | |
| code. njs_vm_call() was used to invoke a single function, while | |
| njs_vm_run() was used to run global code as well to process the events. | |
| At first invocation njs_vm_run() executed global code, all the next | |
| invocations it processed pending events. | |
| The solution is splitting njs_vm_run() into two functions. One for | |
| events processing and another for running the global code. | |
| diff --git a/nginx/ngx_http_js_module.c b/nginx/ngx_http_js_module.c | |
| --- a/nginx/ngx_http_js_module.c | |
| +++ b/nginx/ngx_http_js_module.c | |
| @@ -913,7 +913,7 @@ ngx_http_js_init_vm(ngx_http_request_t * | |
| cln->handler = ngx_http_js_cleanup_ctx; | |
| cln->data = ctx; | |
| - if (njs_vm_run(ctx->vm) == NJS_ERROR) { | |
| + if (njs_vm_run_global(ctx->vm) == NJS_ERROR) { | |
| njs_vm_retval_to_ext_string(ctx->vm, &exception); | |
| ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
| diff --git a/nginx/ngx_stream_js_module.c b/nginx/ngx_stream_js_module.c | |
| --- a/nginx/ngx_stream_js_module.c | |
| +++ b/nginx/ngx_stream_js_module.c | |
| @@ -727,7 +727,7 @@ ngx_stream_js_init_vm(ngx_stream_session | |
| cln->handler = ngx_stream_js_cleanup_ctx; | |
| cln->data = ctx; | |
| - if (njs_vm_run(ctx->vm) == NJS_ERROR) { | |
| + if (njs_vm_run_global(ctx->vm) == NJS_ERROR) { | |
| njs_vm_retval_to_ext_string(ctx->vm, &exception); | |
| ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, | |
| diff --git a/njs/njs.c b/njs/njs.c | |
| --- a/njs/njs.c | |
| +++ b/njs/njs.c | |
| @@ -575,27 +575,26 @@ njs_vm_post_event(njs_vm_t *vm, njs_vm_e | |
| nxt_int_t | |
| njs_vm_run(njs_vm_t *vm) | |
| { | |
| - nxt_int_t ret; | |
| - | |
| if (nxt_slow_path(vm->backtrace != NULL)) { | |
| nxt_array_reset(vm->backtrace); | |
| } | |
| + return njs_vm_handle_events(vm); | |
| +} | |
| + | |
| + | |
| +nxt_int_t | |
| +njs_vm_run_global(njs_vm_t *vm) | |
| +{ | |
| + njs_ret_t ret; | |
| + | |
| ret = njs_vmcode_interpreter(vm); | |
| if (ret == NJS_STOP) { | |
| - ret = njs_vm_handle_events(vm); | |
| + ret = NJS_OK; | |
| } | |
| - switch (ret) { | |
| - case NJS_STOP: | |
| - return NJS_OK; | |
| - | |
| - case NXT_AGAIN: | |
| - case NXT_ERROR: | |
| - default: | |
| - return ret; | |
| - } | |
| + return ret; | |
| } | |
| @@ -633,7 +632,7 @@ njs_vm_handle_events(njs_vm_t *vm) | |
| } | |
| } | |
| - return njs_is_pending_events(vm) ? NJS_AGAIN : NJS_STOP; | |
| + return njs_is_pending_events(vm) ? NJS_AGAIN : NJS_OK; | |
| } | |
| diff --git a/njs/njs.h b/njs/njs.h | |
| --- a/njs/njs.h | |
| +++ b/njs/njs.h | |
| @@ -162,8 +162,6 @@ NXT_EXPORT void njs_vm_destroy(njs_vm_t | |
| NXT_EXPORT nxt_int_t njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end); | |
| NXT_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external); | |
| -NXT_EXPORT nxt_int_t njs_vm_call(njs_vm_t *vm, njs_function_t *function, | |
| - const njs_value_t *args, nxt_uint_t nargs); | |
| NXT_EXPORT njs_vm_event_t njs_vm_add_event(njs_vm_t *vm, | |
| njs_function_t *function, nxt_uint_t once, njs_host_event_t host_ev, | |
| @@ -173,8 +171,35 @@ NXT_EXPORT nxt_int_t njs_vm_pending(njs_ | |
| NXT_EXPORT nxt_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, | |
| const njs_value_t *args, nxt_uint_t nargs); | |
| +/* | |
| + * Runs the specified function with provided arguments. | |
| + * NJS_OK successful run. | |
| + * NJS_ERROR some exception or internal error happens. | |
| + * | |
| + * njs_vm_retval(vm) can be used to get the retval or exception value. | |
| + */ | |
| +NXT_EXPORT nxt_int_t njs_vm_call(njs_vm_t *vm, njs_function_t *function, | |
| + const njs_value_t *args, nxt_uint_t nargs); | |
| + | |
| +/* | |
| + * Runs posted events. | |
| + * NJS_OK successfully processed all posted events, no more events. | |
| + * NJS_AGAIN successfully processed all events, some posted events are | |
| + * still pending. | |
| + * NJS_ERROR some exception or internal error happens. | |
| + * njs_vm_retval(vm) can be used to get the retval or exception value. | |
| + */ | |
| NXT_EXPORT nxt_int_t njs_vm_run(njs_vm_t *vm); | |
| +/* | |
| + * Runs the global code. | |
| + * NJS_OK successful run. | |
| + * NJS_ERROR some exception or internal error happens. | |
| + * | |
| + * njs_vm_retval(vm) can be used to get the retval or exception value. | |
| + */ | |
| +NXT_EXPORT nxt_int_t njs_vm_run_global(njs_vm_t *vm); | |
| + | |
| NXT_EXPORT const njs_extern_t *njs_vm_external_prototype(njs_vm_t *vm, | |
| njs_external_t *external); | |
| NXT_EXPORT nxt_int_t njs_vm_external_create(njs_vm_t *vm, | |
| diff --git a/njs/njs_shell.c b/njs/njs_shell.c | |
| --- a/njs/njs_shell.c | |
| +++ b/njs/njs_shell.c | |
| @@ -490,7 +490,7 @@ njs_process_script(njs_vm_t *vm, njs_opt | |
| printf("\n"); | |
| } | |
| - ret = njs_vm_run(vm); | |
| + ret = njs_vm_run_global(vm); | |
| } | |
| if (njs_vm_retval_dump(vm, out, 1) != NXT_OK) { | |
| diff --git a/njs/test/njs_interactive_test.c b/njs/test/njs_interactive_test.c | |
| --- a/njs/test/njs_interactive_test.c | |
| +++ b/njs/test/njs_interactive_test.c | |
| @@ -285,7 +285,7 @@ njs_interactive_test(nxt_bool_t verbose) | |
| ret = njs_vm_compile(vm, &start, end); | |
| if (ret == NXT_OK) { | |
| - ret = njs_vm_run(vm); | |
| + ret = njs_vm_run_global(vm); | |
| } | |
| } | |
| diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c | |
| --- a/njs/test/njs_unit_test.c | |
| +++ b/njs/test/njs_unit_test.c | |
| @@ -11481,7 +11481,7 @@ njs_unit_test(njs_unit_test_t tests[], s | |
| goto done; | |
| } | |
| - ret = njs_vm_run(nvm); | |
| + ret = njs_vm_run_global(nvm); | |
| if (njs_vm_retval_to_ext_string(nvm, &s) != NXT_OK) { | |
| printf("njs_vm_retval_to_ext_string() failed\n"); | |
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1544527174 -10800 | |
| # Tue Dec 11 14:19:34 2018 +0300 | |
| # Node ID 0e05190227e09c39aeca91ccaf9099b91b63b222 | |
| # Parent 141759f986b49a4721c2541b1b836db25bf35621 | |
| njs_vm_pending() is split in njs_vm_posted() and njs_vm_waiting(). | |
| There are two types of events in njs: | |
| Posted - are ready to be executed by njs_vm_run(). | |
| Waiting - await external async events. | |
| diff --git a/njs/njs.c b/njs/njs.c | |
| --- a/njs/njs.c | |
| +++ b/njs/njs.c | |
| @@ -196,7 +196,7 @@ njs_vm_destroy(njs_vm_t *vm) | |
| njs_event_t *event; | |
| nxt_lvlhsh_each_t lhe; | |
| - if (njs_is_pending_events(vm)) { | |
| + if (njs_waiting_events(vm)) { | |
| nxt_lvlhsh_each_init(&lhe, &njs_event_hash_proto); | |
| for ( ;; ) { | |
| @@ -538,9 +538,16 @@ njs_vm_del_event(njs_vm_t *vm, njs_vm_ev | |
| nxt_int_t | |
| -njs_vm_pending(njs_vm_t *vm) | |
| +njs_vm_waiting(njs_vm_t *vm) | |
| { | |
| - return njs_is_pending_events(vm); | |
| + return njs_waiting_events(vm); | |
| +} | |
| + | |
| + | |
| +nxt_int_t | |
| +njs_vm_posted(njs_vm_t *vm) | |
| +{ | |
| + return njs_posted_events(vm); | |
| } | |
| @@ -632,7 +639,7 @@ njs_vm_handle_events(njs_vm_t *vm) | |
| } | |
| } | |
| - return njs_is_pending_events(vm) ? NJS_AGAIN : NJS_OK; | |
| + return njs_posted_events(vm) ? NJS_AGAIN : NJS_OK; | |
| } | |
| diff --git a/njs/njs.h b/njs/njs.h | |
| --- a/njs/njs.h | |
| +++ b/njs/njs.h | |
| @@ -167,11 +167,23 @@ NXT_EXPORT njs_vm_event_t njs_vm_add_eve | |
| njs_function_t *function, nxt_uint_t once, njs_host_event_t host_ev, | |
| njs_event_destructor_t destructor); | |
| NXT_EXPORT void njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event); | |
| -NXT_EXPORT nxt_int_t njs_vm_pending(njs_vm_t *vm); | |
| NXT_EXPORT nxt_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, | |
| const njs_value_t *args, nxt_uint_t nargs); | |
| /* | |
| + * Returns 1 if async events are present. | |
| + */ | |
| +NXT_EXPORT nxt_int_t njs_vm_waiting(njs_vm_t *vm); | |
| + | |
| +/* | |
| + * Returns 1 if posted events are ready to be executed. | |
| + */ | |
| +NXT_EXPORT nxt_int_t njs_vm_posted(njs_vm_t *vm); | |
| + | |
| +#define njs_vm_pending(vm) (njs_vm_waiting(vm) || njs_vm_posted(vm)) | |
| + | |
| + | |
| +/* | |
| * Runs the specified function with provided arguments. | |
| * NJS_OK successful run. | |
| * NJS_ERROR some exception or internal error happens. | |
| diff --git a/njs/njs_event.h b/njs/njs_event.h | |
| --- a/njs/njs_event.h | |
| +++ b/njs/njs_event.h | |
| @@ -12,7 +12,9 @@ | |
| #define NJS_EVENT_DELETE 2 | |
| -#define njs_is_pending_events(vm) (!nxt_lvlhsh_is_empty(&(vm)->events_hash)) | |
| +#define njs_waiting_events(vm) (!nxt_lvlhsh_is_empty(&(vm)->events_hash)) | |
| + | |
| +#define njs_posted_events(vm) (!nxt_queue_is_empty(&(vm)->posted_events)) | |
| typedef struct { | |
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1544527175 -10800 | |
| # Tue Dec 11 14:19:35 2018 +0300 | |
| # Node ID 7c78f2d37e824f99ee0c7b202f002094cb66f3e7 | |
| # Parent 0e05190227e09c39aeca91ccaf9099b91b63b222 | |
| Interactive shell: initial support of posted events. | |
| diff --git a/njs/njs_shell.c b/njs/njs_shell.c | |
| --- a/njs/njs_shell.c | |
| +++ b/njs/njs_shell.c | |
| @@ -54,7 +54,7 @@ static nxt_int_t njs_interactive_shell(n | |
| njs_vm_opt_t *vm_options); | |
| static nxt_int_t njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options); | |
| static nxt_int_t njs_process_script(njs_vm_t *vm, njs_opts_t *opts, | |
| - const nxt_str_t *script, nxt_str_t *out); | |
| + const nxt_str_t *script); | |
| static nxt_int_t njs_editline_init(njs_vm_t *vm); | |
| static char **njs_completion_handler(const char *text, int start, int end); | |
| static char *njs_completion_generator(const char *text, int state); | |
| @@ -297,7 +297,7 @@ static nxt_int_t | |
| njs_interactive_shell(njs_opts_t *opts, njs_vm_opt_t *vm_options) | |
| { | |
| njs_vm_t *vm; | |
| - nxt_str_t line, out; | |
| + nxt_str_t line; | |
| vm = njs_vm_create(vm_options); | |
| if (vm == NULL) { | |
| @@ -335,9 +335,7 @@ njs_interactive_shell(njs_opts_t *opts, | |
| add_history((char *) line.start); | |
| - njs_process_script(vm, opts, &line, &out); | |
| - | |
| - printf("%.*s\n", (int) out.length, out.start); | |
| + njs_process_script(vm, opts, &line); | |
| /* editline allocs a new buffer every time. */ | |
| free(line.start); | |
| @@ -357,7 +355,7 @@ njs_process_file(njs_opts_t *opts, njs_v | |
| ssize_t n; | |
| njs_vm_t *vm; | |
| nxt_int_t ret; | |
| - nxt_str_t out, script; | |
| + nxt_str_t script; | |
| struct stat sb; | |
| file = opts->file; | |
| @@ -448,9 +446,8 @@ njs_process_file(njs_opts_t *opts, njs_v | |
| goto done; | |
| } | |
| - ret = njs_process_script(vm, opts, &script, &out); | |
| + ret = njs_process_script(vm, opts, &script); | |
| if (ret != NXT_OK) { | |
| - fprintf(stderr, "%.*s\n", (int) out.length, out.start); | |
| ret = NXT_ERROR; | |
| goto done; | |
| } | |
| @@ -473,9 +470,27 @@ close_fd: | |
| } | |
| +static void | |
| +njs_output(njs_vm_t *vm, njs_opts_t *opts, njs_ret_t ret) | |
| +{ | |
| + nxt_str_t out; | |
| + | |
| + if (njs_vm_retval_dump(vm, &out, 1) != NXT_OK) { | |
| + out = nxt_string_value("failed to get retval from VM"); | |
| + ret = NJS_ERROR; | |
| + } | |
| + | |
| + if (ret != NJS_OK) { | |
| + fprintf(stderr, "%.*s\n", (int) out.length, out.start); | |
| + | |
| + } else if (opts->interactive) { | |
| + printf("%.*s\n", (int) out.length, out.start); | |
| + } | |
| +} | |
| + | |
| + | |
| static nxt_int_t | |
| -njs_process_script(njs_vm_t *vm, njs_opts_t *opts, const nxt_str_t *script, | |
| - nxt_str_t *out) | |
| +njs_process_script(njs_vm_t *vm, njs_opts_t *opts, const nxt_str_t *script) | |
| { | |
| u_char *start; | |
| nxt_int_t ret; | |
| @@ -493,9 +508,17 @@ njs_process_script(njs_vm_t *vm, njs_opt | |
| ret = njs_vm_run_global(vm); | |
| } | |
| - if (njs_vm_retval_dump(vm, out, 1) != NXT_OK) { | |
| - *out = nxt_string_value("failed to get retval from VM"); | |
| - return NXT_ERROR; | |
| + njs_output(vm, opts, ret); | |
| + | |
| + if (ret == NJS_OK) { | |
| + while (njs_vm_posted(vm)) { | |
| + ret = njs_vm_run(vm); | |
| + | |
| + if (ret == NJS_ERROR) { | |
| + njs_output(vm, opts, ret); | |
| + return ret; | |
| + } | |
| + } | |
| } | |
| return ret; | |
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1544551224 -10800 | |
| # Tue Dec 11 21:00:24 2018 +0300 | |
| # Node ID fb6163c8a1a967dc7facfa3a826bafff61234d67 | |
| # Parent 7c78f2d37e824f99ee0c7b202f002094cb66f3e7 | |
| Interactive shell: immediate events support. | |
| diff --git a/njs/njs.c b/njs/njs.c | |
| --- a/njs/njs.c | |
| +++ b/njs/njs.c | |
| @@ -625,7 +625,7 @@ njs_vm_handle_events(njs_vm_t *vm) | |
| ev = nxt_queue_link_data(link, njs_event_t, link); | |
| if (ev->once) { | |
| - njs_del_event(vm, ev, NJS_EVENT_DELETE); | |
| + njs_del_event(vm, ev, NJS_EVENT_RELEASE | NJS_EVENT_DELETE); | |
| } else { | |
| ev->posted = 0; | |
| diff --git a/njs/njs_shell.c b/njs/njs_shell.c | |
| --- a/njs/njs_shell.c | |
| +++ b/njs/njs_shell.c | |
| @@ -40,7 +40,6 @@ typedef struct { | |
| typedef struct { | |
| size_t index; | |
| size_t length; | |
| - njs_vm_t *vm; | |
| nxt_array_t *completions; | |
| nxt_array_t *suffix_completions; | |
| nxt_lvlhsh_each_t lhe; | |
| @@ -48,14 +47,25 @@ typedef struct { | |
| } njs_completion_t; | |
| +typedef struct { | |
| + njs_vm_t *vm; | |
| + | |
| + nxt_lvlhsh_t events; | |
| + uint64_t time; | |
| + | |
| + njs_completion_t completion; | |
| +} njs_console_t; | |
| + | |
| + | |
| static nxt_int_t njs_get_options(njs_opts_t *opts, int argc, char **argv); | |
| -static nxt_int_t njs_externals_init(njs_vm_t *vm); | |
| +static nxt_int_t njs_console_init(njs_console_t *console, njs_vm_t *vm); | |
| +static nxt_int_t njs_externals_init(njs_console_t *console, njs_vm_t *vm); | |
| static nxt_int_t njs_interactive_shell(njs_opts_t *opts, | |
| njs_vm_opt_t *vm_options); | |
| static nxt_int_t njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options); | |
| -static nxt_int_t njs_process_script(njs_vm_t *vm, njs_opts_t *opts, | |
| +static nxt_int_t njs_process_script(njs_console_t *console, njs_opts_t *opts, | |
| const nxt_str_t *script); | |
| -static nxt_int_t njs_editline_init(njs_vm_t *vm); | |
| +static nxt_int_t njs_editline_init(void); | |
| static char **njs_completion_handler(const char *text, int start, int end); | |
| static char *njs_completion_generator(const char *text, int state); | |
| @@ -70,6 +80,15 @@ static njs_ret_t njs_ext_console_time(nj | |
| static njs_ret_t njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, | |
| nxt_uint_t nargs, njs_index_t unused); | |
| +static njs_host_event_t njs_console_set_timer(njs_external_ptr_t external, | |
| + uint64_t delay, njs_vm_event_t vm_event); | |
| +static void njs_console_clear_timer(njs_external_ptr_t external, | |
| + njs_host_event_t event); | |
| + | |
| +static nxt_int_t lvlhsh_key_test(nxt_lvlhsh_query_t *lhq, void *data); | |
| +static void *lvlhsh_pool_alloc(void *pool, size_t size, nxt_uint_t nalloc); | |
| +static void lvlhsh_pool_free(void *pool, void *p, size_t size); | |
| + | |
| static njs_external_t njs_ext_console[] = { | |
| @@ -150,10 +169,22 @@ static njs_external_t njs_externals[] = | |
| }; | |
| -static njs_completion_t njs_completion; | |
| +static const nxt_lvlhsh_proto_t lvlhsh_proto nxt_aligned(64) = { | |
| + NXT_LVLHSH_LARGE_SLAB, | |
| + 0, | |
| + lvlhsh_key_test, | |
| + lvlhsh_pool_alloc, | |
| + lvlhsh_pool_free, | |
| +}; | |
| -static uint64_t njs_console_time = UINT64_MAX; | |
| +static njs_vm_ops_t njs_console_ops = { | |
| + njs_console_set_timer, | |
| + njs_console_clear_timer | |
| +}; | |
| + | |
| + | |
| +static njs_console_t njs_console; | |
| int | |
| @@ -182,6 +213,8 @@ main(int argc, char **argv) | |
| vm_options.accumulative = opts.interactive; | |
| vm_options.backtrace = 1; | |
| vm_options.sandbox = opts.sandbox; | |
| + vm_options.ops = &njs_console_ops; | |
| + vm_options.external = &njs_console; | |
| if (opts.interactive) { | |
| ret = njs_interactive_shell(&opts, &vm_options); | |
| @@ -259,7 +292,26 @@ njs_get_options(njs_opts_t *opts, int ar | |
| static nxt_int_t | |
| -njs_externals_init(njs_vm_t *vm) | |
| +njs_console_init(njs_console_t *console, njs_vm_t *vm) | |
| +{ | |
| + console->vm = vm; | |
| + | |
| + nxt_lvlhsh_init(&console->events); | |
| + | |
| + console->time = UINT64_MAX; | |
| + | |
| + console->completion.completions = njs_vm_completions(vm, NULL); | |
| + if (console->completion.completions == NULL) { | |
| + return NXT_ERROR; | |
| + } | |
| + | |
| + return NXT_OK; | |
| +} | |
| + | |
| + | |
| + | |
| +static nxt_int_t | |
| +njs_externals_init(njs_console_t *console, njs_vm_t *vm) | |
| { | |
| nxt_uint_t ret; | |
| njs_value_t *value; | |
| @@ -279,7 +331,7 @@ njs_externals_init(njs_vm_t *vm) | |
| return NXT_ERROR; | |
| } | |
| - ret = njs_vm_external_create(vm, value, proto, NULL); | |
| + ret = njs_vm_external_create(vm, value, proto, &njs_console); | |
| if (ret != NXT_OK) { | |
| return NXT_ERROR; | |
| } | |
| @@ -289,6 +341,11 @@ njs_externals_init(njs_vm_t *vm) | |
| return NXT_ERROR; | |
| } | |
| + ret = njs_console_init(console, vm); | |
| + if (ret != NXT_OK) { | |
| + return NXT_ERROR; | |
| + } | |
| + | |
| return NXT_OK; | |
| } | |
| @@ -299,22 +356,22 @@ njs_interactive_shell(njs_opts_t *opts, | |
| njs_vm_t *vm; | |
| nxt_str_t line; | |
| + if (njs_editline_init() != NXT_OK) { | |
| + fprintf(stderr, "failed to init completions\n"); | |
| + return NXT_ERROR; | |
| + } | |
| + | |
| vm = njs_vm_create(vm_options); | |
| if (vm == NULL) { | |
| fprintf(stderr, "failed to create vm\n"); | |
| return NXT_ERROR; | |
| } | |
| - if (njs_externals_init(vm) != NXT_OK) { | |
| + if (njs_externals_init(&njs_console, vm) != NXT_OK) { | |
| fprintf(stderr, "failed to add external protos\n"); | |
| return NXT_ERROR; | |
| } | |
| - if (njs_editline_init(vm) != NXT_OK) { | |
| - fprintf(stderr, "failed to init completions\n"); | |
| - return NXT_ERROR; | |
| - } | |
| - | |
| if (!opts->quiet) { | |
| printf("interactive njs %s\n\n", NJS_VERSION); | |
| @@ -335,7 +392,7 @@ njs_interactive_shell(njs_opts_t *opts, | |
| add_history((char *) line.start); | |
| - njs_process_script(vm, opts, &line); | |
| + njs_process_script(&njs_console, opts, &line); | |
| /* editline allocs a new buffer every time. */ | |
| free(line.start); | |
| @@ -439,14 +496,14 @@ njs_process_file(njs_opts_t *opts, njs_v | |
| goto done; | |
| } | |
| - ret = njs_externals_init(vm); | |
| + ret = njs_externals_init(&njs_console, vm); | |
| if (ret != NXT_OK) { | |
| fprintf(stderr, "failed to add external protos\n"); | |
| ret = NXT_ERROR; | |
| goto done; | |
| } | |
| - ret = njs_process_script(vm, opts, &script); | |
| + ret = njs_process_script(&njs_console, opts, &script); | |
| if (ret != NXT_OK) { | |
| ret = NXT_ERROR; | |
| goto done; | |
| @@ -490,11 +547,36 @@ njs_output(njs_vm_t *vm, njs_opts_t *opt | |
| static nxt_int_t | |
| -njs_process_script(njs_vm_t *vm, njs_opts_t *opts, const nxt_str_t *script) | |
| +njs_process_events(njs_console_t *console, njs_opts_t *opts) | |
| +{ | |
| + njs_vm_event_t event; | |
| + nxt_lvlhsh_each_t lhe; | |
| + | |
| + nxt_lvlhsh_each_init(&lhe, &lvlhsh_proto); | |
| + | |
| + for ( ;; ) { | |
| + event = nxt_lvlhsh_each(&console->events, &lhe); | |
| + | |
| + if (event == NULL) { | |
| + break; | |
| + } | |
| + | |
| + njs_vm_post_event(console->vm, event, NULL, 0); | |
| + } | |
| + | |
| + return NXT_OK; | |
| +} | |
| + | |
| + | |
| +static nxt_int_t | |
| +njs_process_script(njs_console_t *console, njs_opts_t *opts, | |
| + const nxt_str_t *script) | |
| { | |
| u_char *start; | |
| + njs_vm_t *vm; | |
| nxt_int_t ret; | |
| + vm = console->vm; | |
| start = script->start; | |
| ret = njs_vm_compile(vm, &start, start + script->length); | |
| @@ -510,14 +592,29 @@ njs_process_script(njs_vm_t *vm, njs_opt | |
| njs_output(vm, opts, ret); | |
| - if (ret == NJS_OK) { | |
| - while (njs_vm_posted(vm)) { | |
| - ret = njs_vm_run(vm); | |
| + for ( ;; ) { | |
| + if (!njs_vm_pending(vm)) { | |
| + break; | |
| + } | |
| - if (ret == NJS_ERROR) { | |
| - njs_output(vm, opts, ret); | |
| - return ret; | |
| - } | |
| + ret = njs_process_events(console, opts); | |
| + if (nxt_slow_path(ret != NXT_OK)) { | |
| + fprintf(stderr, "njs_process_events() failed\n"); | |
| + ret = NJS_ERROR; | |
| + } | |
| + | |
| + if (njs_vm_waiting(vm) && !njs_vm_posted(vm)) { | |
| + /*TODO: async events. */ | |
| + | |
| + fprintf(stderr, "njs_process_script(): " | |
| + "async events unsupported\n"); | |
| + ret = NJS_ERROR; | |
| + } | |
| + | |
| + ret = njs_vm_run(vm); | |
| + | |
| + if (ret == NJS_ERROR) { | |
| + njs_output(vm, opts, ret); | |
| } | |
| } | |
| @@ -526,7 +623,7 @@ njs_process_script(njs_vm_t *vm, njs_opt | |
| static nxt_int_t | |
| -njs_editline_init(njs_vm_t *vm) | |
| +njs_editline_init(void) | |
| { | |
| rl_completion_append_character = '\0'; | |
| rl_attempted_completion_function = njs_completion_handler; | |
| @@ -534,13 +631,6 @@ njs_editline_init(njs_vm_t *vm) | |
| setlocale(LC_ALL, ""); | |
| - njs_completion.completions = njs_vm_completions(vm, NULL); | |
| - if (njs_completion.completions == NULL) { | |
| - return NXT_ERROR; | |
| - } | |
| - | |
| - njs_completion.vm = vm; | |
| - | |
| return NXT_OK; | |
| } | |
| @@ -571,10 +661,12 @@ njs_completion_generator(const char *tex | |
| size_t len; | |
| nxt_str_t expression, *suffix; | |
| const char *p; | |
| + njs_vm_t *vm; | |
| njs_variable_t *var; | |
| njs_completion_t *cmpl; | |
| - cmpl = &njs_completion; | |
| + vm = njs_console.vm; | |
| + cmpl = &njs_console.completion; | |
| if (state == 0) { | |
| cmpl->phase = 0; | |
| @@ -589,12 +681,12 @@ next: | |
| switch (cmpl->phase) { | |
| case NJS_COMPLETION_VAR: | |
| - if (cmpl->vm->parser == NULL) { | |
| + if (vm->parser == NULL) { | |
| njs_next_phase(cmpl); | |
| } | |
| for ( ;; ) { | |
| - var = nxt_lvlhsh_each(&cmpl->vm->parser->scope->variables, | |
| + var = nxt_lvlhsh_each(&vm->parser->scope->variables, | |
| &cmpl->lhe); | |
| if (var == NULL) { | |
| @@ -630,8 +722,7 @@ next: | |
| expression.start = (u_char *) text; | |
| expression.length = p - text; | |
| - cmpl->suffix_completions = njs_vm_completions(cmpl->vm, | |
| - &expression); | |
| + cmpl->suffix_completions = njs_vm_completions(vm, &expression); | |
| if (cmpl->suffix_completions == NULL) { | |
| njs_next_phase(cmpl); | |
| } | |
| @@ -797,15 +888,22 @@ static njs_ret_t | |
| njs_ext_console_time(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| njs_index_t unused) | |
| { | |
| + njs_console_t *console; | |
| + | |
| if (!njs_value_is_void(njs_arg(args, nargs, 1))) { | |
| njs_vm_error(vm, "labels not implemented"); | |
| return NJS_ERROR; | |
| } | |
| + console = njs_vm_external(vm, njs_arg(args, nargs, 0)); | |
| + if (nxt_slow_path(console == NULL)) { | |
| + return NJS_ERROR; | |
| + } | |
| + | |
| + console->time = nxt_time(); | |
| + | |
| vm->retval = njs_value_void; | |
| - njs_console_time = nxt_time(); | |
| - | |
| return NJS_OK; | |
| } | |
| @@ -814,7 +912,8 @@ static njs_ret_t | |
| njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| njs_index_t unused) | |
| { | |
| - uint64_t ns, ms; | |
| + uint64_t ns, ms; | |
| + njs_console_t *console; | |
| ns = nxt_time(); | |
| @@ -823,16 +922,21 @@ njs_ext_console_time_end(njs_vm_t *vm, n | |
| return NJS_ERROR; | |
| } | |
| - if (nxt_fast_path(njs_console_time != UINT64_MAX)) { | |
| + console = njs_vm_external(vm, njs_arg(args, nargs, 0)); | |
| + if (nxt_slow_path(console == NULL)) { | |
| + return NJS_ERROR; | |
| + } | |
| - ns = ns - njs_console_time; | |
| + if (nxt_fast_path(console->time != UINT64_MAX)) { | |
| + | |
| + ns = ns - console->time; | |
| ms = ns / 1000000; | |
| ns = ns % 1000000; | |
| printf("default: %" PRIu64 ".%06" PRIu64 "ms\n", ms, ns); | |
| - njs_console_time = UINT64_MAX; | |
| + console->time = UINT64_MAX; | |
| } else { | |
| printf("Timer \"default\" doesn’t exist.\n"); | |
| @@ -842,3 +946,85 @@ njs_ext_console_time_end(njs_vm_t *vm, n | |
| return NJS_OK; | |
| } | |
| + | |
| + | |
| +static njs_host_event_t | |
| +njs_console_set_timer(njs_external_ptr_t external, uint64_t delay, | |
| + njs_vm_event_t vm_event) | |
| +{ | |
| + nxt_int_t ret; | |
| + njs_console_t *console; | |
| + nxt_lvlhsh_query_t lhq; | |
| + | |
| + if (delay != 0) { | |
| + fprintf(stderr, "njs_console_set_timer(): async timers unsupported\n"); | |
| + return NULL; | |
| + } | |
| + | |
| + console = external; | |
| + | |
| + lhq.key.start = (u_char *) &vm_event; | |
| + lhq.key.length = sizeof(vm_event); | |
| + lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); | |
| + | |
| + lhq.replace = 0; | |
| + lhq.value = vm_event; | |
| + lhq.proto = &lvlhsh_proto; | |
| + lhq.pool = console->vm->mem_cache_pool; | |
| + | |
| + ret = nxt_lvlhsh_insert(&console->events, &lhq); | |
| + if (nxt_slow_path(ret != NXT_OK)) { | |
| + return NULL; | |
| + } | |
| + | |
| + return (njs_host_event_t) vm_event; | |
| +} | |
| + | |
| + | |
| +static void | |
| +njs_console_clear_timer(njs_external_ptr_t external, njs_host_event_t event) | |
| +{ | |
| + nxt_int_t ret; | |
| + njs_console_t *console; | |
| + nxt_lvlhsh_query_t lhq; | |
| + | |
| + console = external; | |
| + | |
| + lhq.key.start = (u_char *) &event; | |
| + lhq.key.length = sizeof(event); | |
| + lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); | |
| + | |
| + lhq.proto = &lvlhsh_proto; | |
| + lhq.pool = console->vm->mem_cache_pool; | |
| + | |
| + ret = nxt_lvlhsh_delete(&console->events, &lhq); | |
| + if (ret != NXT_OK) { | |
| + printf("nxt_lvlhsh_delete() failed\n"); | |
| + } | |
| +} | |
| + | |
| + | |
| +static nxt_int_t | |
| +lvlhsh_key_test(nxt_lvlhsh_query_t *lhq, void *data) | |
| +{ | |
| + if (memcmp(&data, lhq->key.start, sizeof(njs_vm_event_t)) == 0) { | |
| + return NXT_OK; | |
| + } | |
| + | |
| + return NXT_DECLINED; | |
| +} | |
| + | |
| + | |
| +static void * | |
| +lvlhsh_pool_alloc(void *pool, size_t size, nxt_uint_t nalloc) | |
| +{ | |
| + return nxt_mem_cache_align(pool, size, size); | |
| +} | |
| + | |
| + | |
| +static void | |
| +lvlhsh_pool_free(void *pool, void *p, size_t size) | |
| +{ | |
| + nxt_mem_cache_free(pool, p); | |
| +} | |
| + | |
| diff --git a/njs/test/njs_expect_test.exp b/njs/test/njs_expect_test.exp | |
| --- a/njs/test/njs_expect_test.exp | |
| +++ b/njs/test/njs_expect_test.exp | |
| @@ -292,6 +292,55 @@ njs_test { | |
| "'й'"} | |
| } | |
| +# Immediate events | |
| + | |
| +njs_test { | |
| + {"var a = 1 + 1; setTimeout(function (x) {a = x}, 0, 'a'); a\r\n" | |
| + "2"} | |
| + {"a\r\n" | |
| + "a\r\n'a'"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"setTimeout(function () {}, 1, 'a')\r\n" | |
| + "njs_console_set_timer(): async timers unsupported"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var a = 1 + 1; setTimeout(function (x) { setTimeout(function (y) {a = y}, 0, x)}, 0, 'a'); a\r\n" | |
| + "2"} | |
| + {"a\r\n" | |
| + "a\r\n'a'"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var a = 1 + 1; setImmediate(function (x) { setImmediate(function (y) {a = y}, x)}, 'a'); a\r\n" | |
| + "2"} | |
| + {"a\r\n" | |
| + "a\r\n'a'"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var i = 0; (function x() { if (i < 10) setImmediate(x); i++; })()\r\n" | |
| + "undefined"} | |
| + {"i\r\n" | |
| + "i\r\n11"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var a = 0, t = setImmediate(function() {a = 1}); clearTimeout(t)\r\n" | |
| + "undefined"} | |
| + {"a\r\n" | |
| + "a\r\n0"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var i = 0; (function x() { if (i < 3) setImmediate(x); i++; throw 'Oops';})()\r\n" | |
| + "Oops"} | |
| + {"i\r\n" | |
| + "i\r\n4"} | |
| +} | |
| + | |
| # require('fs') | |
| set file [open njs_test_file w] | |
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1544618207 -10800 | |
| # Wed Dec 12 15:36:47 2018 +0300 | |
| # Node ID 2db0a59ce692db14af778253d51def8a471e5a9a | |
| # Parent fb6163c8a1a967dc7facfa3a826bafff61234d67 | |
| Added support of native functions call in njs_vm_call(). | |
| diff --git a/njs/njs.c b/njs/njs.c | |
| --- a/njs/njs.c | |
| +++ b/njs/njs.c | |
| @@ -461,9 +461,10 @@ nxt_int_t | |
| njs_vm_call(njs_vm_t *vm, njs_function_t *function, const njs_value_t *args, | |
| nxt_uint_t nargs) | |
| { | |
| - u_char *current; | |
| - njs_ret_t ret; | |
| - njs_value_t *this; | |
| + u_char *current; | |
| + njs_ret_t ret; | |
| + njs_value_t *this; | |
| + njs_continuation_t *cont; | |
| static const njs_vmcode_stop_t stop[] = { | |
| { .code = { .operation = njs_vmcode_stop, | |
| @@ -474,17 +475,36 @@ njs_vm_call(njs_vm_t *vm, njs_function_t | |
| this = (njs_value_t *) &njs_value_void; | |
| - ret = njs_function_frame(vm, function, this, args, nargs, 0); | |
| - if (nxt_slow_path(ret != NXT_OK)) { | |
| - return ret; | |
| - } | |
| + current = vm->current; | |
| - current = vm->current; | |
| - vm->current = (u_char *) stop; | |
| + if (function->native) { | |
| + ret = njs_function_native_frame(vm, function, this, &args[0], | |
| + nargs, NJS_CONTINUATION_SIZE, 0); | |
| + if (ret != NJS_OK) { | |
| + return NJS_ERROR; | |
| + } | |
| - ret = njs_function_call(vm, NJS_INDEX_GLOBAL_RETVAL, 0); | |
| - if (nxt_slow_path(ret == NXT_ERROR)) { | |
| - return ret; | |
| + cont = njs_vm_continuation(vm); | |
| + | |
| + cont->function = function->u.native; | |
| + cont->args_types = function->args_types; | |
| + cont->retval = NJS_INDEX_GLOBAL_RETVAL; | |
| + | |
| + cont->return_address = (u_char *) stop; | |
| + vm->current = (u_char *) njs_continuation_nexus; | |
| + | |
| + } else { | |
| + ret = njs_function_frame(vm, function, this, args, nargs, 0); | |
| + if (nxt_slow_path(ret != NXT_OK)) { | |
| + return ret; | |
| + } | |
| + | |
| + vm->current = (u_char *) stop; | |
| + | |
| + ret = njs_function_call(vm, NJS_INDEX_GLOBAL_RETVAL, 0); | |
| + if (nxt_slow_path(ret == NXT_ERROR)) { | |
| + return ret; | |
| + } | |
| } | |
| ret = njs_vmcode_interpreter(vm); | |
| diff --git a/njs/njs_function.c b/njs/njs_function.c | |
| --- a/njs/njs_function.c | |
| +++ b/njs/njs_function.c | |
| @@ -178,7 +178,7 @@ njs_function_arguments_thrower(njs_vm_t | |
| njs_ret_t | |
| njs_function_native_frame(njs_vm_t *vm, njs_function_t *function, | |
| - const njs_value_t *this, njs_value_t *args, nxt_uint_t nargs, | |
| + const njs_value_t *this, const njs_value_t *args, nxt_uint_t nargs, | |
| size_t reserve, nxt_bool_t ctor) | |
| { | |
| size_t size; | |
| diff --git a/njs/njs_function.h b/njs/njs_function.h | |
| --- a/njs/njs_function.h | |
| +++ b/njs/njs_function.h | |
| @@ -162,7 +162,7 @@ njs_ret_t njs_function_constructor(njs_v | |
| njs_ret_t njs_function_apply(njs_vm_t *vm, njs_function_t *function, | |
| njs_value_t *args, nxt_uint_t nargs, njs_index_t retval); | |
| njs_ret_t njs_function_native_frame(njs_vm_t *vm, njs_function_t *function, | |
| - const njs_value_t *this, njs_value_t *args, nxt_uint_t nargs, | |
| + const njs_value_t *this, const njs_value_t *args, nxt_uint_t nargs, | |
| size_t reserve, nxt_bool_t ctor); | |
| njs_ret_t njs_function_frame(njs_vm_t *vm, njs_function_t *function, | |
| const njs_value_t *this, const njs_value_t *args, nxt_uint_t nargs, | |
| diff --git a/njs/test/njs_expect_test.exp b/njs/test/njs_expect_test.exp | |
| --- a/njs/test/njs_expect_test.exp | |
| +++ b/njs/test/njs_expect_test.exp | |
| @@ -341,6 +341,11 @@ njs_test { | |
| "i\r\n4"} | |
| } | |
| +njs_test { | |
| + {"var t = setImmediate(console.log, 'a', 'aa')\r\n" | |
| + "undefined\r\n'a' 'aa'"} | |
| +} | |
| + | |
| # require('fs') | |
| set file [open njs_test_file w] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment