details: https://hg.nginx.org/njs/rev/cb3e068a511c branches: changeset: 2290:cb3e068a511c user: Dmitry Volyntsev <xei...@nginx.com> date: Thu Feb 22 20:25:43 2024 -0800 description: Shell: added QuickJS engine support.
diffstat: auto/expect | 22 +- auto/make | 23 +- auto/options | 2 + auto/quickjs | 55 + auto/summary | 4 + configure | 1 + external/njs_shell.c | 2225 ++++++++++++++++++++++++++++++++++++++++----- src/njs_builtin.c | 3 + src/test/njs_unit_test.c | 4 +- test/setup | 5 + test/shell_test.exp | 361 +------- test/shell_test_njs.exp | 418 ++++++++ test/test262 | 5 + 13 files changed, 2531 insertions(+), 597 deletions(-) diffs (truncated from 3866 to 1000 lines): diff -r 272af619b821 -r cb3e068a511c auto/expect --- a/auto/expect Thu Feb 22 17:38:58 2024 -0800 +++ b/auto/expect Thu Feb 22 20:25:43 2024 -0800 @@ -20,11 +20,31 @@ fi if [ $njs_found = yes -a $NJS_HAVE_READLINE = YES ]; then cat << END >> $NJS_MAKEFILE -shell_test: njs test/shell_test.exp +shell_test_njs: njs test/shell_test.exp PATH=$NJS_BUILD_DIR:\$(PATH) LANG=C.UTF-8 TERM=screen \ expect -f test/shell_test.exp + PATH=$NJS_BUILD_DIR:\$(PATH) LANG=C.UTF-8 TERM=screen \ + expect -f test/shell_test_njs.exp END +if [ $NJS_HAVE_QUICKJS = YES ]; then + cat << END >> $NJS_MAKEFILE + +shell_test: shell_test_njs shell_test_quickjs + +shell_test_quickjs: njs test/shell_test.exp + PATH=$NJS_BUILD_DIR:\$(PATH) LANG=C.UTF-8 TERM=screen NJS_ENGINE=QuickJS \ + expect -f test/shell_test.exp +END + +else + cat << END >> $NJS_MAKEFILE + +shell_test: shell_test_njs +END + +fi + else echo " - expect tests are disabled" diff -r 272af619b821 -r cb3e068a511c auto/make --- a/auto/make Thu Feb 22 17:38:58 2024 -0800 +++ b/auto/make Thu Feb 22 20:25:43 2024 -0800 @@ -241,8 +241,7 @@ lib_test: $NJS_BUILD_DIR/njs_auto_config $NJS_BUILD_DIR/lvlhsh_unit_test $NJS_BUILD_DIR/unicode_unit_test -test262: njs - +test262_njs: njs test/test262 --binary=$NJS_BUILD_DIR/njs unit_test: $NJS_BUILD_DIR/njs_auto_config.h \\ @@ -265,6 +264,26 @@ dist: && echo njs-\$(NJS_VER).tar.gz done END +if [ $NJS_HAVE_QUICKJS = YES ]; then + cat << END >> $NJS_MAKEFILE + +test262: njs test262_njs test262_quickjs + +test262_quickjs: njs + NJS_SKIP_LIST="test/js/promise_rejection_tracker_recursive.t.js \\ +test/js/async_exception_in_await.t.js" \\ + test/test262 --binary='$NJS_BUILD_DIR/njs -n QuickJS -m' +END + +else + cat << END >> $NJS_MAKEFILE + +test262: njs test262_njs +END + +fi + + njs_ts_deps=`echo $NJS_TS_SRCS \ | sed -e "s# *\([^ ][^ ]*\)#\1$njs_regex_cont#g"` diff -r 272af619b821 -r cb3e068a511c auto/options --- a/auto/options Thu Feb 22 17:38:58 2024 -0800 +++ b/auto/options Thu Feb 22 20:25:43 2024 -0800 @@ -14,6 +14,7 @@ NJS_DEBUG_GENERATOR=NO NJS_ADDRESS_SANITIZER=NO NJS_ADDR2LINE=NO +NJS_QUICKJS=YES NJS_OPENSSL=YES NJS_LIBXML2=YES NJS_ZLIB=YES @@ -47,6 +48,7 @@ do --debug-opcode=*) NJS_DEBUG_OPCODE="$value" ;; --debug-generator=*) NJS_DEBUG_GENERATOR="$value" ;; + --no-quickjs) NJS_QUICKJS=NO ;; --no-openssl) NJS_OPENSSL=NO ;; --no-libxml2) NJS_LIBXML2=NO ;; --no-zlib) NJS_ZLIB=NO ;; diff -r 272af619b821 -r cb3e068a511c auto/quickjs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/auto/quickjs Thu Feb 22 20:25:43 2024 -0800 @@ -0,0 +1,55 @@ + +# Copyright (C) Dmitry Volyntsev +# Copyright (C) NGINX, Inc. + + +NJS_QUICKJS_LIB= +NJS_HAVE_QUICKJS=NO + +if [ $NJS_QUICKJS = YES ]; then + njs_found=no + + njs_feature="QuickJS library" + njs_feature_name=NJS_HAVE_QUICKJS + njs_feature_run=yes + njs_feature_incs= + njs_feature_libs="" + njs_feature_test="#if defined(__GNUC__) && (__GNUC__ >= 8) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored \"-Wcast-function-type\" + #endif + + #include <quickjs.h> + + int main() { + JSRuntime *rt; + + rt = JS_NewRuntime(); + JS_FreeRuntime(rt); + return 0; + }" + . auto/feature + + if [ $njs_found = no ]; then + njs_feature="QuickJS library -lquickjs.lto" + njs_feature_incs="/usr/include/quickjs/" + njs_feature_libs="-L/usr/lib/quickjs/ -lquickjs.lto -lm -ldl -lpthread" + + . auto/feature + fi + + if [ $njs_found = no ]; then + njs_feature="QuickJS library -lquickjs" + njs_feature_libs="-L/usr/lib/quickjs/ -lquickjs -lm -ldl -lpthread" + + . auto/feature + fi + + if [ $njs_found = yes ]; then + NJS_HAVE_QUICKJS=YES + NJS_QUICKJS_LIB="$njs_feature_libs" + NJS_LIB_INCS="$NJS_LIB_INCS $njs_feature_incs" + NJS_LIB_AUX_LIBS="$NJS_LIB_AUX_LIBS $njs_feature_libs" + fi + +fi diff -r 272af619b821 -r cb3e068a511c auto/summary --- a/auto/summary Thu Feb 22 17:38:58 2024 -0800 +++ b/auto/summary Thu Feb 22 20:25:43 2024 -0800 @@ -18,6 +18,10 @@ if [ $NJS_HAVE_READLINE = YES ]; then echo " + using readline library: $NJS_READLINE_LIB" fi +if [ $NJS_HAVE_QUICKJS = YES ]; then + echo " + using QuickJS library: $NJS_QUICKJS_LIB" +fi + if [ $NJS_HAVE_OPENSSL = YES ]; then echo " + using OpenSSL library: $NJS_OPENSSL_LIB" fi diff -r 272af619b821 -r cb3e068a511c configure --- a/configure Thu Feb 22 17:38:58 2024 -0800 +++ b/configure Thu Feb 22 20:25:43 2024 -0800 @@ -50,6 +50,7 @@ NJS_LIB_AUX_LIBS= . auto/explicit_bzero . auto/pcre . auto/readline +. auto/quickjs . auto/openssl . auto/libxml2 . auto/zlib diff -r 272af619b821 -r cb3e068a511c external/njs_shell.c --- a/external/njs_shell.c Thu Feb 22 17:38:58 2024 -0800 +++ b/external/njs_shell.c Thu Feb 22 20:25:43 2024 -0800 @@ -11,6 +11,21 @@ #include <njs_queue.h> #include <njs_rbtree.h> +#if (NJS_HAVE_QUICKJS) +#if defined(__GNUC__) && (__GNUC__ >= 8) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + +#include <quickjs.h> + +#if defined(__GNUC__) && (__GNUC__ >= 8) +#pragma GCC diagnostic pop +#endif +#define NJS_QUICKJS_VERSION "Unknown version" +#include <pthread.h> +#endif + #if (!defined NJS_FUZZER_TARGET && defined NJS_HAVE_READLINE) #include <locale.h> @@ -38,8 +53,10 @@ typedef struct { uint8_t version; uint8_t ast; uint8_t unhandled_rejection; + uint8_t suppress_stdout; uint8_t opcode_debug; uint8_t generator_debug; + uint8_t can_block; int exit_code; int stack_size; @@ -49,6 +66,11 @@ typedef struct { njs_str_t *paths; char **argv; njs_uint_t argc; + + enum { + NJS_ENGINE_NJS = 0, + NJS_ENGINE_QUICKJS = 1, + } engine; } njs_opts_t; @@ -75,8 +97,19 @@ typedef struct { typedef struct { NJS_RBTREE_NODE (node); - njs_function_t *function; - njs_value_t *args; + union { + struct { + njs_function_t *function; + njs_value_t *args; + } njs; +#if (NJS_HAVE_QUICKJS) + struct { + JSValue function; + JSValue *args; + } qjs; +#endif + } u; + njs_uint_t nargs; uint32_t id; @@ -92,8 +125,18 @@ typedef struct { typedef struct { - void *promise; - njs_opaque_value_t message; + union { + struct { + njs_opaque_value_t promise; + njs_opaque_value_t message; + } njs; +#if (NJS_HAVE_QUICKJS) + struct { + JSValue promise; + JSValue message; + } qjs; +#endif + } u; } njs_rejected_promise_t; @@ -105,8 +148,39 @@ typedef struct { } njs_module_info_t; +typedef struct njs_engine_s njs_engine_t; + + +struct njs_engine_s { + union { + struct { + njs_vm_t *vm; + + njs_opaque_value_t value; + njs_completion_t completion; + } njs; +#if (NJS_HAVE_QUICKJS) + struct { + JSRuntime *rt; + JSContext *ctx; + JSValue value; + } qjs; +#endif + } u; + + njs_int_t (*eval)(njs_engine_t *engine, njs_str_t *script); + njs_int_t (*execute_pending_job)(njs_engine_t *engine); + njs_int_t (*unhandled_rejection)(njs_engine_t *engine); + njs_int_t (*process_events)(njs_engine_t *engine); + njs_int_t (*destroy)(njs_engine_t *engine); + njs_int_t (*output)(njs_engine_t *engine, njs_int_t ret); + + unsigned type; + njs_mp_t *pool; +}; + typedef struct { - njs_vm_t *vm; + njs_engine_t *engine; uint32_t event_id; njs_rbtree_t events; /* njs_ev_t * */ @@ -119,25 +193,57 @@ typedef struct { njs_arr_t *rejected_promises; njs_bool_t suppress_stdout; - - njs_completion_t completion; + njs_bool_t interactive; + njs_bool_t module; + char **argv; + njs_uint_t argc; + +#if (NJS_HAVE_QUICKJS) + JSValue process; + + njs_queue_t agents; + njs_queue_t reports; + pthread_mutex_t agent_mutex; + pthread_cond_t agent_cond; + pthread_mutex_t report_mutex; +#endif } njs_console_t; +#if (NJS_HAVE_QUICKJS) +typedef struct { + njs_queue_link_t link; + pthread_t tid; + njs_console_t *console; + char *script; + JSValue broadcast_func; + njs_bool_t broadcast_pending; + JSValue broadcast_sab; + uint8_t *broadcast_sab_buf; + size_t broadcast_sab_size; + int32_t broadcast_val; +} njs_262agent_t; + + +typedef struct { + njs_queue_link_t link; + char *str; +} njs_agent_report_t; +#endif + + static njs_int_t njs_main(njs_opts_t *opts); -static njs_int_t njs_console_init(njs_vm_t *vm, njs_console_t *console); -static void njs_console_output(njs_vm_t *vm, njs_value_t *value, - njs_int_t ret); +static njs_int_t njs_console_init(njs_opts_t *opts, njs_console_t *console); static njs_int_t njs_externals_init(njs_vm_t *vm); -static njs_vm_t *njs_create_vm(njs_opts_t *opts); -static void njs_process_output(njs_vm_t *vm, njs_value_t *value, njs_int_t ret); +static njs_engine_t *njs_create_engine(njs_opts_t *opts); static njs_int_t njs_process_file(njs_opts_t *opts); -static njs_int_t njs_process_script(njs_vm_t *vm, void *runtime, - const njs_str_t *script); +static njs_int_t njs_process_script(njs_engine_t *engine, + njs_console_t *console, njs_str_t *script); #ifndef NJS_FUZZER_TARGET static njs_int_t njs_options_parse(njs_opts_t *opts, int argc, char **argv); +static njs_int_t njs_options_parse_engine(njs_opts_t *opts, const char *engine); static njs_int_t njs_options_add_path(njs_opts_t *opts, char *path, size_t len); static void njs_options_free(njs_opts_t *opts); @@ -166,6 +272,9 @@ static void njs_console_log(njs_log_leve static void njs_console_logger(njs_log_level_t level, const u_char *start, size_t length); +static njs_int_t njs_console_time(njs_console_t *console, njs_str_t *name); +static void njs_console_time_end(njs_console_t *console, njs_str_t *name, + uint64_t time); static intptr_t njs_event_rbtree_compare(njs_rbtree_node_t *node1, njs_rbtree_node_t *node2); static uint64_t njs_time(void); @@ -317,8 +426,8 @@ static njs_console_t njs_console; static njs_int_t njs_main(njs_opts_t *opts) { - njs_vm_t *vm; - njs_int_t ret; + njs_int_t ret; + njs_engine_t *engine; njs_mm_denormals(opts->denormals); @@ -339,6 +448,12 @@ njs_main(njs_opts_t *opts) } } + ret = njs_console_init(opts, &njs_console); + if (njs_slow_path(ret != NJS_OK)) { + njs_stderror("njs_console_init() failed\n"); + return NJS_ERROR; + } + #if (!defined NJS_FUZZER_TARGET && defined NJS_HAVE_READLINE) if (opts->interactive) { @@ -349,13 +464,13 @@ njs_main(njs_opts_t *opts) #endif if (opts->command.length != 0) { - vm = njs_create_vm(opts); - if (vm == NULL) { + engine = njs_create_engine(opts); + if (engine == NULL) { return NJS_ERROR; } - ret = njs_process_script(vm, njs_vm_external_ptr(vm), &opts->command); - njs_vm_destroy(vm); + ret = njs_process_script(engine, &njs_console, &opts->command); + engine->destroy(engine); } else { ret = njs_process_file(opts); @@ -426,6 +541,10 @@ njs_options_parse(njs_opts_t *opts, int " -g enable generator debug.\n" #endif " -j <size> set the maximum stack size in bytes.\n" + " -m load as ES6 module (script is default).\n" +#ifdef NJS_HAVE_QUICKJS + " -n njs|QuickJS set JS engine (njs is default)\n" +#endif #ifdef NJS_DEBUG_OPCODE " -o enable opcode debug.\n" #endif @@ -433,15 +552,14 @@ njs_options_parse(njs_opts_t *opts, int " -q disable interactive introduction prompt.\n" " -r ignore unhandled promise rejection.\n" " -s sandbox mode.\n" - " -t script|module source code type (script is default).\n" " -v print njs version and exit.\n" " -u disable \"unsafe\" mode.\n" " script.js | - run code from a file or stdin.\n"; - ret = NJS_DONE; - opts->denormals = 1; + opts->can_block = 1; opts->exit_code = EXIT_FAILURE; + opts->engine = NJS_ENGINE_NJS; opts->unhandled_rejection = 1; p = getenv("NJS_EXIT_CODE"); @@ -449,6 +567,24 @@ njs_options_parse(njs_opts_t *opts, int opts->exit_code = atoi(p); } + p = getenv("NJS_CAN_BLOCK"); + if (p != NULL) { + opts->can_block = atoi(p); + } + + p = getenv("NJS_LOAD_AS_MODULE"); + if (p != NULL) { + opts->module = 1; + } + + p = getenv("NJS_ENGINE"); + if (p != NULL) { + ret = njs_options_parse_engine(opts, p); + if (ret != NJS_OK) { + return NJS_ERROR; + } + } + start = getenv("NJS_PATH"); if (start != NULL) { for ( ;; ) { @@ -486,7 +622,7 @@ njs_options_parse(njs_opts_t *opts, int case '?': case 'h': njs_printf("%*s", njs_length(help), help); - return ret; + return NJS_DONE; case 'a': opts->ast = 1; @@ -541,6 +677,23 @@ njs_options_parse(njs_opts_t *opts, int njs_stderror("option \"-j\" requires argument\n"); return NJS_ERROR; + case 'm': + opts->module = 1; + break; + + case 'n': + if (++i < argc) { + ret = njs_options_parse_engine(opts, argv[i]); + if (ret != NJS_OK) { + return NJS_ERROR; + } + + break; + } + + njs_stderror("option \"-n\" requires argument\n"); + return NJS_ERROR; + #ifdef NJS_DEBUG_OPCODE case 'o': opts->opcode_debug = 1; @@ -573,22 +726,6 @@ njs_options_parse(njs_opts_t *opts, int opts->sandbox = 1; break; - case 't': - if (++i < argc) { - if (strcmp(argv[i], "module") == 0) { - opts->module = 1; - - } else if (strcmp(argv[i], "script") != 0) { - njs_stderror("option \"-t\" unexpected source type: %s\n", - argv[i]); - return NJS_ERROR; - } - - break; - } - - njs_stderror("option \"-t\" requires source type\n"); - return NJS_ERROR; case 'v': case 'V': opts->version = 1; @@ -608,6 +745,40 @@ njs_options_parse(njs_opts_t *opts, int done: +#ifdef NJS_HAVE_QUICKJS + if (opts->engine == NJS_ENGINE_QUICKJS) { + if (opts->ast) { + njs_stderror("option \"-a\" is not supported for quickjs\n"); + return NJS_ERROR; + } + + if (opts->disassemble) { + njs_stderror("option \"-d\" is not supported for quickjs\n"); + return NJS_ERROR; + } + + if (opts->generator_debug) { + njs_stderror("option \"-g\" is not supported for quickjs\n"); + return NJS_ERROR; + } + + if (opts->opcode_debug) { + njs_stderror("option \"-o\" is not supported for quickjs\n"); + return NJS_ERROR; + } + + if (opts->sandbox) { + njs_stderror("option \"-s\" is not supported for quickjs\n"); + return NJS_ERROR; + } + + if (opts->safe) { + njs_stderror("option \"-u\" is not supported for quickjs\n"); + return NJS_ERROR; + } + } +#endif + opts->argc = njs_max(argc - i + 1, 2); opts->argv = malloc(sizeof(char*) * opts->argc); if (opts->argv == NULL) { @@ -626,6 +797,26 @@ done: static njs_int_t +njs_options_parse_engine(njs_opts_t *opts, const char *engine) +{ + if (strncasecmp(engine, "njs", 3) == 0) { + opts->engine = NJS_ENGINE_NJS; + +#ifdef NJS_HAVE_QUICKJS + } else if (strncasecmp(engine, "QuickJS", 7) == 0) { + opts->engine = NJS_ENGINE_QUICKJS; +#endif + + } else { + njs_stderror("unknown engine \"%s\"\n", engine); + return NJS_ERROR; + } + + return NJS_OK; +} + + +static njs_int_t njs_options_add_path(njs_opts_t *opts, char *path, size_t len) { njs_str_t *paths; @@ -675,10 +866,7 @@ LLVMFuzzerTestOneInput(const uint8_t* da opts.file = (char *) "fuzzer"; opts.command.start = (u_char *) data; opts.command.length = size; - - njs_memzero(&njs_console, sizeof(njs_console_t)); - - njs_console.suppress_stdout = 1; + opts.suppress_stdout = 1; return njs_main(&opts); } @@ -686,23 +874,31 @@ LLVMFuzzerTestOneInput(const uint8_t* da #endif static njs_int_t -njs_console_init(njs_vm_t *vm, njs_console_t *console) +njs_console_init(njs_opts_t *opts, njs_console_t *console) { - console->vm = vm; - - console->event_id = 0; + njs_memzero(console, sizeof(njs_console_t)); + njs_rbtree_init(&console->events, njs_event_rbtree_compare); njs_queue_init(&console->posted_events); njs_queue_init(&console->labels); - njs_memzero(&console->cwd, sizeof(njs_str_t)); - - console->rejected_promises = NULL; - - console->completion.completions = njs_vm_completions(vm, NULL); - if (console->completion.completions == NULL) { - return NJS_ERROR; + console->interactive = opts->interactive; + console->suppress_stdout = opts->suppress_stdout; + console->module = opts->module; + console->argv = opts->argv; + console->argc = opts->argc; + +#if (NJS_HAVE_QUICKJS) + if (opts->engine == NJS_ENGINE_QUICKJS) { + njs_queue_init(&console->agents); + njs_queue_init(&console->reports); + pthread_mutex_init(&console->report_mutex, NULL); + pthread_mutex_init(&console->agent_mutex, NULL); + pthread_cond_init(&console->agent_cond, NULL); + + console->process = JS_UNDEFINED; } +#endif return NJS_OK; } @@ -741,7 +937,7 @@ njs_externals_init(njs_vm_t *vm) static const njs_str_t set_immediate = njs_str("setImmediate"); static const njs_str_t clear_timeout = njs_str("clearTimeout"); - console = njs_vm_options(vm)->external; + console = njs_vm_external_ptr(vm); njs_console_proto_id = njs_vm_external_prototype(vm, njs_ext_console, njs_nitems(njs_ext_console)); @@ -803,11 +999,6 @@ njs_externals_init(njs_vm_t *vm) return NJS_ERROR; } - ret = njs_console_init(vm, console); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; - } - return NJS_OK; } @@ -830,7 +1021,9 @@ njs_rejection_tracker(njs_vm_t *vm, njs_ promise_obj = njs_value_ptr(promise); for (i = 0; i < length; i++) { - if (rejected_promise[i].promise == promise_obj) { + if (njs_value_ptr(njs_value_arg(&rejected_promise[i].u.njs.promise)) + == promise_obj) + { njs_arr_remove(console->rejected_promises, &rejected_promise[i]); @@ -842,7 +1035,7 @@ njs_rejection_tracker(njs_vm_t *vm, njs_ } if (console->rejected_promises == NULL) { - console->rejected_promises = njs_arr_create(njs_vm_memory_pool(vm), 4, + console->rejected_promises = njs_arr_create(console->engine->pool, 4, sizeof(njs_rejected_promise_t)); if (njs_slow_path(console->rejected_promises == NULL)) { return; @@ -854,8 +1047,8 @@ njs_rejection_tracker(njs_vm_t *vm, njs_ return; } - rejected_promise->promise = njs_value_ptr(promise); - njs_value_assign(&rejected_promise->message, reason); + njs_value_assign(&rejected_promise->u.njs.promise, promise); + njs_value_assign(&rejected_promise->u.njs.message, reason); } @@ -968,7 +1161,7 @@ njs_module_read(njs_mp_t *mp, int fd, nj text->length = sb.st_size; - text->start = njs_mp_alloc(mp, text->length); + text->start = njs_mp_alloc(mp, text->length + 1); if (text->start == NULL) { goto fail; } @@ -979,6 +1172,8 @@ njs_module_read(njs_mp_t *mp, int fd, nj goto fail; } + text->start[text->length] = '\0'; + return NJS_OK; fail: @@ -1034,13 +1229,13 @@ current_dir: static njs_int_t -njs_console_set_cwd(njs_vm_t *vm, njs_console_t *console, njs_str_t *file) +njs_console_set_cwd(njs_console_t *console, njs_str_t *file) { njs_str_t cwd; njs_file_dirname(file, &cwd); - console->cwd.start = njs_mp_alloc(njs_vm_memory_pool(vm), cwd.length); + console->cwd.start = njs_mp_alloc(console->engine->pool, cwd.length); if (njs_slow_path(console->cwd.start == NULL)) { return NJS_ERROR; } @@ -1086,7 +1281,7 @@ njs_module_loader(njs_vm_t *vm, njs_exte prev_cwd = console->cwd; - ret = njs_console_set_cwd(vm, console, &info.file); + ret = njs_console_set_cwd(console, &info.file); if (njs_slow_path(ret != NJS_OK)) { njs_vm_internal_error(vm, "while setting cwd for \"%V\" module", &info.file); @@ -1107,8 +1302,8 @@ njs_module_loader(njs_vm_t *vm, njs_exte } -static njs_vm_t * -njs_create_vm(njs_opts_t *opts) +static njs_int_t +njs_engine_njs_init(njs_engine_t *engine, njs_opts_t *opts) { njs_vm_t *vm; njs_int_t ret; @@ -1147,7 +1342,12 @@ njs_create_vm(njs_opts_t *opts) vm = njs_vm_create(&vm_options); if (vm == NULL) { njs_stderror("failed to create vm\n"); - return NULL; + return NJS_ERROR; + } + + engine->u.njs.completion.completions = njs_vm_completions(vm, NULL); + if (engine->u.njs.completion.completions == NULL) { + return NJS_ERROR; } if (opts->unhandled_rejection) { @@ -1155,30 +1355,77 @@ njs_create_vm(njs_opts_t *opts) njs_vm_external_ptr(vm)); } - ret = njs_console_set_cwd(vm, njs_vm_external_ptr(vm), &vm_options.file); + ret = njs_console_set_cwd(njs_vm_external_ptr(vm), &vm_options.file); if (njs_slow_path(ret != NJS_OK)) { njs_stderror("failed to set cwd\n"); - return NULL; + return NJS_ERROR; } njs_vm_set_module_loader(vm, njs_module_loader, opts); - return vm; + engine->u.njs.vm = vm; + + return NJS_OK; +} + + +static njs_int_t +njs_engine_njs_destroy(njs_engine_t *engine) +{ + njs_vm_destroy(engine->u.njs.vm); + njs_mp_destroy(engine->pool); + + return NJS_OK; } -static void -njs_console_output(njs_vm_t *vm, njs_value_t *value, njs_int_t ret) +static njs_int_t +njs_engine_njs_eval(njs_engine_t *engine, njs_str_t *script) { - njs_str_t out; + u_char *start, *end; + njs_int_t ret; + + start = script->start; + end = start + script->length; + + ret = njs_vm_compile(engine->u.njs.vm, &start, end); + + if (ret == NJS_OK && start == end) { + return njs_vm_start(engine->u.njs.vm, + njs_value_arg(&engine->u.njs.value)); + } + + return NJS_ERROR; +} + + +static njs_int_t +njs_engine_njs_execute_pending_job(njs_engine_t *engine) +{ + return njs_vm_execute_pending_job(engine->u.njs.vm); +} + + +static njs_int_t +njs_engine_njs_output(njs_engine_t *engine, njs_int_t ret) +{ + njs_vm_t *vm; + njs_str_t out; + njs_console_t *console; + + vm = engine->u.njs.vm; + console = njs_vm_external_ptr(vm); if (ret == NJS_OK) { - if (njs_vm_value_dump(vm, &out, value, 0, 1) != NJS_OK) { - njs_stderror("Shell:failed to get retval from VM\n"); - return; - } - - if (njs_vm_options(vm)->interactive) { + if (console->interactive) { + if (njs_vm_value_dump(vm, &out, njs_value_arg(&engine->u.njs.value), + 0, 1) + != NJS_OK) + { + njs_stderror("Shell:failed to get retval from VM\n"); + return NJS_ERROR; + } + njs_print(out.start, out.length); njs_print("\n", 1); } @@ -1187,11 +1434,13 @@ njs_console_output(njs_vm_t *vm, njs_val njs_vm_exception_string(vm, &out); njs_stderror("Thrown:\n%V\n", &out); } + + return NJS_OK; } static njs_int_t -njs_process_events(void *runtime) +njs_engine_njs_process_events(njs_engine_t *engine) { njs_ev_t *ev; njs_vm_t *vm; @@ -1201,14 +1450,8 @@ njs_process_events(void *runtime) njs_queue_link_t *link; njs_opaque_value_t retval; - if (runtime == NULL) { - njs_stderror("njs_process_events(): no runtime\n"); - return NJS_ERROR; - } - - console = runtime; - vm = console->vm; - + vm = engine->u.njs.vm; + console = njs_vm_external_ptr(vm); events = &console->posted_events; for ( ;; ) { @@ -1221,17 +1464,14 @@ njs_process_events(void *runtime) ev = njs_queue_link_data(link, njs_ev_t, link); njs_queue_remove(&ev->link); - ev->link.prev = NULL; - ev->link.next = NULL; - njs_rbtree_delete(&console->events, &ev->node); - ret = njs_vm_invoke(vm, ev->function, ev->args, ev->nargs, + ret = njs_vm_invoke(vm, ev->u.njs.function, ev->u.njs.args, ev->nargs, njs_value_arg(&retval)); if (ret == NJS_ERROR) { - njs_process_output(vm, njs_value_arg(&retval), ret); - - if (!njs_vm_options(vm)->interactive) { + njs_engine_njs_output(engine, ret); + + if (!console->interactive) { return NJS_ERROR; } } @@ -1246,14 +1486,16 @@ njs_process_events(void *runtime) static njs_int_t -njs_unhandled_rejection(void *runtime) +njs_engine_njs_unhandled_rejection(njs_engine_t *engine) { + njs_vm_t *vm; njs_int_t ret; njs_str_t message; njs_console_t *console; njs_rejected_promise_t *rejected_promise; - console = runtime; + vm = engine->u.njs.vm; + console = njs_vm_external_ptr(vm); if (console->rejected_promises == NULL || console->rejected_promises->items == 0) @@ -1263,14 +1505,13 @@ njs_unhandled_rejection(void *runtime) rejected_promise = console->rejected_promises->start; - ret = njs_vm_value_to_string(console->vm, &message, - njs_value_arg(&rejected_promise->message)); + ret = njs_vm_value_to_string(vm, &message, + njs_value_arg(&rejected_promise->u.njs.message)); if (njs_slow_path(ret != NJS_OK)) { return -1; } - njs_vm_error(console->vm, "unhandled promise rejection: %V", - &message); + njs_vm_error(vm, "unhandled promise rejection: %V", &message); njs_arr_destroy(console->rejected_promises); console->rejected_promises = NULL; @@ -1278,6 +1519,1483 @@ njs_unhandled_rejection(void *runtime) return 1; } +#ifdef NJS_HAVE_QUICKJS + +static JSValue +njs_qjs_console_log(JSContext *ctx, JSValueConst this_val, int argc, + JSValueConst *argv, int magic) +{ + int i; + size_t len; + const char *str; + + for (i = 0; i < argc; i++) { + str = JS_ToCStringLen(ctx, &len, argv[i]); + if (!str) { + return JS_EXCEPTION; + } + + njs_console_logger(magic, (const u_char*) str, len); + JS_FreeCString(ctx, str); + } + + return JS_UNDEFINED; +} + + +static JSValue +njs_qjs_console_time(JSContext *ctx, JSValueConst this_val, int argc, + JSValueConst *argv) +{ + njs_str_t name; + const char *str; + njs_console_t *console; + _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel