Welcome! Log In Create A New Profile

Advanced

[njs] Shell: added QuickJS engine support.

Dmitry Volyntsev
February 23, 2024 12:22AM
details: https://hg.nginx.org/njs/rev/cb3e068a511c
branches:
changeset: 2290:cb3e068a511c
user: Dmitry Volyntsev <xeioex@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
Subject Author Views Posted

[njs] Shell: added QuickJS engine support.

Dmitry Volyntsev 243 February 23, 2024 12:22AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 239
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 500 on July 15, 2024
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready