[njs] QuickJS: reworked process object.

noreply at nginx.com noreply at nginx.com
Wed Nov 6 16:17:02 UTC 2024


details:   https://github.com/nginx/njs/commit/98fff325573c3554203e7cbc467066f7c8a45c2c
branches:  master
commit:    98fff325573c3554203e7cbc467066f7c8a45c2c
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu, 31 Oct 2024 17:47:41 -0700
description:
QuickJS: reworked process object.


---
 external/njs_shell.c | 122 +++---------------------------
 nginx/ngx_js.c       |   9 +++
 src/qjs.c            | 204 ++++++++++++++++++++++++++++++++++++++++-----------
 src/qjs.h            |   2 +-
 4 files changed, 182 insertions(+), 155 deletions(-)

diff --git a/external/njs_shell.c b/external/njs_shell.c
index 30d4d8c6..776c2536 100644
--- a/external/njs_shell.c
+++ b/external/njs_shell.c
@@ -1901,15 +1901,17 @@ njs_qjs_clear_timeout(JSContext *ctx, JSValueConst this_val, int argc,
 }
 
 
+static JSValue
+njs_qjs_console_to_string_tag(JSContext *ctx, JSValueConst this_val)
+{
+    return JS_NewString(ctx, "Console");
+}
+
+
 static JSValue
 njs_qjs_process_getter(JSContext *ctx, JSValueConst this_val)
 {
-    char           **ep;
-    JSAtom         atom;
-    JSValue        obj, val, str, name, env;
-    njs_int_t      ret;
-    njs_uint_t     i;
-    const char     *entry, *value;
+    JSValue         obj;
     njs_console_t  *console;
 
     console = JS_GetRuntimeOpaque(JS_GetRuntime(ctx));
@@ -1918,106 +1920,8 @@ njs_qjs_process_getter(JSContext *ctx, JSValueConst this_val)
         return JS_DupValue(ctx, console->process);
     }
 
-    obj = JS_NewObject(ctx);
-    if (JS_IsException(obj)) {
-        return JS_EXCEPTION;
-    }
-
-    ret = qjs_set_to_string_tag(ctx, obj, "process");
-    if (ret == -1) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-
-    val = JS_NewArray(ctx);
-    if (JS_IsException(val)) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-
-    ret = JS_SetPropertyStr(ctx, obj, "argv", val);
-    if (ret == -1) {
-        JS_FreeValue(ctx, obj);
-        JS_FreeValue(ctx, val);
-        return JS_EXCEPTION;
-    }
-
-    for (i = 0; i < console->argc; i++) {
-        str = JS_NewStringLen(ctx, console->argv[i],
-                              njs_strlen(console->argv[i]));
-        if (JS_IsException(str)) {
-            JS_FreeValue(ctx, obj);
-            return JS_EXCEPTION;
-        }
-
-        ret = JS_DefinePropertyValueUint32(ctx, val, i, str, JS_PROP_C_W_E);
-        if (ret == -1) {
-            JS_FreeValue(ctx, obj);
-            return JS_EXCEPTION;
-        }
-    }
-
-    env = JS_NewObject(ctx);
+    obj = qjs_process_object(ctx, console->argc, (const char **) console->argv);
     if (JS_IsException(obj)) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-
-    ret = JS_SetPropertyStr(ctx, obj, "env", env);
-    if (ret == -1) {
-        JS_FreeValue(ctx, obj);
-        JS_FreeValue(ctx, env);
-        return JS_EXCEPTION;
-    }
-
-    ep = environ;
-
-    while (*ep != NULL) {
-        entry = *ep++;
-
-        value = (const char *) njs_strchr(entry, '=');
-        if (njs_slow_path(value == NULL)) {
-            continue;
-        }
-
-        str = JS_UNDEFINED;
-        name = JS_NewStringLen(ctx, entry, value - entry);
-        if (JS_IsException(name)) {
-            goto error;
-        }
-
-        str = JS_NewStringLen(ctx, value, njs_strlen(value));
-        if (JS_IsException(str)) {
-            goto error;
-        }
-
-        atom = JS_ValueToAtom(ctx, name);
-        if (atom == JS_ATOM_NULL) {
-            goto error;
-        }
-
-        ret = JS_DefinePropertyValue(ctx, env, atom, str, JS_PROP_C_W_E);
-        JS_FreeAtom(ctx, atom);
-        if (ret == -1) {
-error:
-            JS_FreeValue(ctx, name);
-            JS_FreeValue(ctx, str);
-            JS_FreeValue(ctx, obj);
-            return JS_EXCEPTION;
-        }
-
-        JS_FreeValue(ctx, name);
-    }
-
-    ret = JS_SetPropertyStr(ctx, obj, "pid", JS_NewInt32(ctx, getpid()));
-    if (ret == -1) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-
-    ret = JS_SetPropertyStr(ctx, obj, "ppid", JS_NewInt32(ctx, getppid()));
-    if (ret == -1) {
-        JS_FreeValue(ctx, obj);
         return JS_EXCEPTION;
     }
 
@@ -2583,6 +2487,7 @@ static const JSCFunctionListEntry njs_qjs_global_proto[] = {
 
 
 static const JSCFunctionListEntry njs_qjs_console_proto[] = {
+    JS_CGETSET_DEF("[Symbol.toStringTag]", njs_qjs_console_to_string_tag, NULL),
     JS_CFUNC_MAGIC_DEF("error", 0, njs_qjs_console_log, NJS_LOG_ERROR),
     JS_CFUNC_MAGIC_DEF("info", 0, njs_qjs_console_log, NJS_LOG_INFO),
     JS_CFUNC_MAGIC_DEF("log", 0, njs_qjs_console_log, NJS_LOG_INFO),
@@ -2759,13 +2664,6 @@ njs_engine_qjs_init(njs_engine_t *engine, njs_opts_t *opts)
         goto done;
     }
 
-    ret = qjs_set_to_string_tag(ctx, obj, "Console");
-    if (ret == -1) {
-        njs_stderror("qjs_set_to_string_tag() failed\n");
-        ret = NJS_ERROR;
-        goto done;
-    }
-
     JS_SetOpaque(obj, &njs_console);
 
     JS_SetPropertyFunctionList(ctx, obj, njs_qjs_console_proto,
diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c
index f70288cf..1ac53baa 100644
--- a/nginx/ngx_js.c
+++ b/nginx/ngx_js.c
@@ -70,6 +70,7 @@ static ngx_int_t ngx_engine_qjs_pending(ngx_engine_t *engine);
 static ngx_int_t ngx_engine_qjs_string(ngx_engine_t *e,
     njs_opaque_value_t *value, ngx_str_t *str);
 
+static JSValue ngx_qjs_process_getter(JSContext *ctx, JSValueConst this_val);
 static JSValue ngx_qjs_ext_set_timeout(JSContext *cx, JSValueConst this_val,
     int argc, JSValueConst *argv, int immediate);
 static JSValue ngx_qjs_ext_clear_timeout(JSContext *cx, JSValueConst this_val,
@@ -457,6 +458,7 @@ static const JSCFunctionListEntry ngx_qjs_ext_console[] = {
 
 
 static const JSCFunctionListEntry ngx_qjs_ext_global[] = {
+    JS_CGETSET_DEF("process", ngx_qjs_process_getter, NULL),
     JS_CFUNC_MAGIC_DEF("setTimeout", 1, ngx_qjs_ext_set_timeout, 0),
     JS_CFUNC_MAGIC_DEF("setImmediate", 1, ngx_qjs_ext_set_timeout, 1),
     JS_CFUNC_DEF("clearTimeout", 1, ngx_qjs_ext_clear_timeout),
@@ -1566,6 +1568,13 @@ ngx_qjs_clear_timer(ngx_qjs_event_t *event)
 }
 
 
+static JSValue
+ngx_qjs_process_getter(JSContext *cx, JSValueConst this_val)
+{
+    return qjs_process_object(cx, ngx_argc, (const char **) ngx_argv);
+}
+
+
 static JSValue
 ngx_qjs_ext_set_timeout(JSContext *cx, JSValueConst this_val, int argc,
     JSValueConst *argv, int immediate)
diff --git a/src/qjs.c b/src/qjs.c
index 3d378fcc..b529f1bb 100644
--- a/src/qjs.c
+++ b/src/qjs.c
@@ -7,14 +7,42 @@
 #include <qjs.h>
 #include <njs.h> /* NJS_VERSION */
 
+#include <sys/types.h>
+#include <unistd.h>
+
+
+extern char  **environ;
+
 
 static JSValue qjs_njs_getter(JSContext *ctx, JSValueConst this_val);
+static JSValue qjs_njs_to_string_tag(JSContext *ctx, JSValueConst this_val);
+static JSValue qjs_process_to_string_tag(JSContext *ctx, JSValueConst this_val);
+static JSValue qjs_process_argv(JSContext *ctx, JSValueConst this_val);
+static JSValue qjs_process_env(JSContext *ctx, JSValueConst this_val);
+static JSValue qjs_process_pid(JSContext *ctx, JSValueConst this_val);
+static JSValue qjs_process_ppid(JSContext *ctx, JSValueConst this_val);
 
 
 static const JSCFunctionListEntry qjs_global_proto[] = {
     JS_CGETSET_DEF("njs", qjs_njs_getter, NULL),
 };
 
+static const JSCFunctionListEntry qjs_njs_proto[] = {
+    JS_CGETSET_DEF("[Symbol.toStringTag]", qjs_njs_to_string_tag, NULL),
+    JS_PROP_STRING_DEF("version", NJS_VERSION, JS_PROP_C_W_E),
+    JS_PROP_INT32_DEF("version_number", NJS_VERSION_NUMBER,
+                      JS_PROP_C_W_E),
+    JS_PROP_STRING_DEF("engine", "QuickJS", JS_PROP_C_W_E),
+};
+
+static const JSCFunctionListEntry qjs_process_proto[] = {
+    JS_CGETSET_DEF("[Symbol.toStringTag]", qjs_process_to_string_tag, NULL),
+    JS_CGETSET_DEF("argv", qjs_process_argv, NULL),
+    JS_CGETSET_DEF("env", qjs_process_env, NULL),
+    JS_CGETSET_DEF("pid", qjs_process_pid, NULL),
+    JS_CGETSET_DEF("ppid", qjs_process_ppid, NULL),
+};
+
 
 JSContext *
 qjs_new_context(JSRuntime *rt, qjs_module_t **addons)
@@ -91,7 +119,6 @@ qjs_new_context(JSRuntime *rt, qjs_module_t **addons)
 static JSValue
 qjs_njs_getter(JSContext *ctx, JSValueConst this_val)
 {
-    int      ret;
     JSValue  obj;
 
     obj = JS_NewObject(ctx);
@@ -99,73 +126,166 @@ qjs_njs_getter(JSContext *ctx, JSValueConst this_val)
         return JS_EXCEPTION;
     }
 
-    ret = qjs_set_to_string_tag(ctx, obj, "njs");
-    if (ret == -1) {
-        JS_FreeValue(ctx, obj);
+    JS_SetPropertyFunctionList(ctx, obj, qjs_njs_proto,
+                               njs_nitems(qjs_njs_proto));
+
+    return obj;
+}
+
+
+static JSValue
+qjs_njs_to_string_tag(JSContext *ctx, JSValueConst this_val)
+{
+    return JS_NewString(ctx, "njs");
+}
+
+
+static JSValue
+qjs_process_to_string_tag(JSContext *ctx, JSValueConst this_val)
+{
+    return JS_NewString(ctx, "process");
+}
+
+
+static JSValue
+qjs_process_argv(JSContext *ctx, JSValueConst this_val)
+{
+    int         i, ret, argc;
+    JSValue     val, str;
+    const char  **argv;
+
+    val = JS_GetPropertyStr(ctx, this_val, "argc");
+    if (JS_IsException(val)) {
         return JS_EXCEPTION;
     }
 
-    ret = JS_SetPropertyStr(ctx, obj, "version_number",
-                            JS_NewInt32(ctx, NJS_VERSION_NUMBER));
-    if (ret == -1) {
-        JS_FreeValue(ctx, obj);
+    if (JS_ToInt32(ctx, &argc, val) < 0) {
         return JS_EXCEPTION;
     }
 
-    ret = JS_SetPropertyStr(ctx, obj, "version",
-                            JS_NewString(ctx, NJS_VERSION));
-    if (ret == -1) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
+    argv = JS_GetOpaque(this_val, JS_GetClassID(this_val));
+    if (argv == NULL) {
+        return JS_NewArray(ctx);
     }
 
-    ret = JS_SetPropertyStr(ctx, obj, "engine", JS_NewString(ctx, "QuickJS"));
-    if (ret == -1) {
-        JS_FreeValue(ctx, obj);
+    val = JS_NewArray(ctx);
+    if (JS_IsException(val)) {
         return JS_EXCEPTION;
     }
 
-    return obj;
+    for (i = 0; i < argc; i++) {
+        str = JS_NewStringLen(ctx, argv[i], njs_strlen(argv[i]));
+        if (JS_IsException(str)) {
+            JS_FreeValue(ctx, val);
+            return JS_EXCEPTION;
+        }
+
+        ret = JS_DefinePropertyValueUint32(ctx, val, i, str, JS_PROP_C_W_E);
+        if (ret < 0) {
+            JS_FreeValue(ctx, str);
+            JS_FreeValue(ctx, val);
+            return JS_EXCEPTION;
+        }
+    }
+
+    return val;
 }
 
 
-int
-qjs_set_to_string_tag(JSContext *ctx, JSValueConst val, const char *tag)
+static JSValue
+qjs_process_env(JSContext *ctx, JSValueConst this_val)
 {
-    int      ret;
-    JSAtom   atom;
-    JSValue  global_obj, symbol, toStringTag;
-
-    global_obj = JS_GetGlobalObject(ctx);
+    int         ret;
+    char        **ep;
+    JSValue     obj;
+    JSAtom      atom;
+    JSValue     str, name;
+    const char  *entry, *value;
 
-    symbol = JS_GetPropertyStr(ctx, global_obj, "Symbol");
-    JS_FreeValue(ctx, global_obj);
-    if (JS_IsException(symbol)) {
-        return -1;
+    obj = JS_NewObject(ctx);
+    if (JS_IsException(obj)) {
+        return JS_EXCEPTION;
     }
 
-    toStringTag = JS_GetPropertyStr(ctx, symbol, "toStringTag");
-    if (JS_IsException(toStringTag)) {
-        JS_FreeValue(ctx, symbol);
-        return -1;
+    ep = environ;
+
+    while (*ep != NULL) {
+        entry = *ep++;
+
+        value = (const char *) njs_strchr(entry, '=');
+        if (value == NULL) {
+            continue;
+        }
+
+        str = JS_UNDEFINED;
+        name = JS_NewStringLen(ctx, entry, value - entry);
+        if (JS_IsException(name)) {
+            goto error;
+        }
+
+        value++;
+
+        str = JS_NewStringLen(ctx, value, njs_strlen(value));
+        if (JS_IsException(str)) {
+            goto error;
+        }
+
+        atom = JS_ValueToAtom(ctx, name);
+        if (atom == JS_ATOM_NULL) {
+            goto error;
+        }
+
+        ret = JS_DefinePropertyValue(ctx, obj, atom, str, JS_PROP_C_W_E);
+        JS_FreeAtom(ctx, atom);
+        if (ret < 0) {
+error:
+            JS_FreeValue(ctx, name);
+            JS_FreeValue(ctx, str);
+            return JS_EXCEPTION;
+        }
+
+        JS_FreeValue(ctx, name);
     }
 
-    atom = JS_ValueToAtom(ctx, toStringTag);
+    return obj;
+}
 
-    JS_FreeValue(ctx, symbol);
-    JS_FreeValue(ctx, toStringTag);
 
-    if (atom == JS_ATOM_NULL) {
-        JS_ThrowInternalError(ctx, "failed to get atom");
-        return -1;
+static JSValue
+qjs_process_pid(JSContext *ctx, JSValueConst this_val)
+{
+    return JS_NewInt32(ctx, getpid());
+}
+
+
+static JSValue
+qjs_process_ppid(JSContext *ctx, JSValueConst this_val)
+{
+    return JS_NewInt32(ctx, getppid());
+}
+
+
+JSValue
+qjs_process_object(JSContext *ctx, int argc, const char **argv)
+{
+    JSValue  obj;
+
+    obj = JS_NewObject(ctx);
+    if (JS_IsException(obj)) {
+        return JS_EXCEPTION;
     }
 
-    ret = JS_DefinePropertyValue(ctx, val, atom, JS_NewString(ctx, tag),
-                                 JS_PROP_C_W_E);
+    JS_SetPropertyFunctionList(ctx, obj, qjs_process_proto,
+                               njs_nitems(qjs_process_proto));
 
-    JS_FreeAtom(ctx, atom);
+    JS_SetOpaque(obj, argv);
 
-    return ret;
+    if (JS_SetPropertyStr(ctx, obj, "argc", JS_NewInt32(ctx, argc)) < 0) {
+        JS_FreeValue(ctx, obj);
+        return JS_EXCEPTION;
+    }
+
+    return obj;
 }
 
 
diff --git a/src/qjs.h b/src/qjs.h
index 2418e6cd..81769abb 100644
--- a/src/qjs.h
+++ b/src/qjs.h
@@ -70,7 +70,7 @@ typedef struct {
 const qjs_buffer_encoding_t *qjs_buffer_encoding(JSContext *ctx,
     JSValueConst value, JS_BOOL thrw);
 
-int qjs_set_to_string_tag(JSContext *ctx, JSValueConst val, const char *tag);
+JSValue qjs_process_object(JSContext *ctx, int argc, const char **argv);
 
 typedef struct {
     int                         tag;


More information about the nginx-devel mailing list