This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch update-quickjs
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 84800246ea5195241efc4beb3cf1fc23adf37771
Author: Nick Vatamaniuc <[email protected]>
AuthorDate: Thu Sep 18 11:45:01 2025 -0400

    Update QuickJS
    
      - New official release: 2025-09-13
      - Fix crash on bytecode read
         
https://github.com/bellard/quickjs/commit/391cd3feff17ebdf572230bd22d1986f18c9f81f)
      - Improve pretty printing of strings
         
https://github.com/bellard/quickjs/commit/8a0a6e92d2fc01331b4a7c80f7d7569625af352a
      - More efficient handling of strings in `JSON.stringify()`
         
https://github.com/bellard/quickjs/commit/9f6c1907316caea933ae3ed9dbfa3f2c4897525c
      - Fix array memory leak:
         
https://github.com/bellard/quickjs/commit/de4d3927b8edff5fbfee1f69cfeef840844259e9
---
 .../patches/01-spidermonkey-185-mode.patch         |   6 +-
 .../patches/02-test262-makefile.patch              |   4 +-
 src/couch_quickjs/patches/03-test262-yield.patch   |   4 +-
 src/couch_quickjs/patches/04-test262-errors.patch  |   4 +-
 src/couch_quickjs/quickjs/Changelog                |   3 +
 src/couch_quickjs/quickjs/VERSION                  |   2 +-
 src/couch_quickjs/quickjs/qjsc.c                   |   3 +
 src/couch_quickjs/quickjs/quickjs.c                | 257 ++++++++++++---------
 src/couch_quickjs/quickjs/quickjs.h                |   4 +-
 src/couch_quickjs/quickjs/run-test262.c            |  43 +++-
 10 files changed, 206 insertions(+), 124 deletions(-)

diff --git a/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch 
b/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch
index 20ac3172e..15443fe4d 100644
--- a/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch
+++ b/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch
@@ -1,6 +1,6 @@
---- quickjs-master/quickjs.c   2025-08-25 12:20:58
-+++ quickjs/quickjs.c  2025-08-25 15:10:50
-@@ -30776,10 +30776,24 @@
+--- quickjs-master/quickjs.c   2025-09-18 04:42:13
++++ quickjs/quickjs.c  2025-09-18 11:43:37
+@@ -30751,10 +30751,24 @@
      if (s->token.val == TOK_FUNCTION ||
          (token_is_pseudo_keyword(s, JS_ATOM_async) &&
           peek_token(s, TRUE) == TOK_FUNCTION)) {
diff --git a/src/couch_quickjs/patches/02-test262-makefile.patch 
b/src/couch_quickjs/patches/02-test262-makefile.patch
index a4fb9b4b1..dd362b8ab 100644
--- a/src/couch_quickjs/patches/02-test262-makefile.patch
+++ b/src/couch_quickjs/patches/02-test262-makefile.patch
@@ -1,5 +1,5 @@
---- quickjs-master/Makefile    2025-08-25 12:20:58
-+++ quickjs/Makefile   2025-08-25 15:27:47
+--- quickjs-master/Makefile    2025-09-18 04:42:13
++++ quickjs/Makefile   2025-09-18 11:43:37
 @@ -53,6 +53,10 @@
  #CONFIG_MSAN=y
  # use UB sanitizer
diff --git a/src/couch_quickjs/patches/03-test262-yield.patch 
b/src/couch_quickjs/patches/03-test262-yield.patch
index 419e609c3..b4ef63866 100644
--- a/src/couch_quickjs/patches/03-test262-yield.patch
+++ b/src/couch_quickjs/patches/03-test262-yield.patch
@@ -1,5 +1,5 @@
---- quickjs-master/tests/test262.patch 2025-08-25 12:20:58
-+++ quickjs/tests/test262.patch        2025-08-25 15:10:50
+--- quickjs-master/tests/test262.patch 2025-09-18 04:42:13
++++ quickjs/tests/test262.patch        2025-09-18 11:43:37
 @@ -14,9 +14,9 @@
  +//  small: 200,
  +//  long: 1000,
diff --git a/src/couch_quickjs/patches/04-test262-errors.patch 
b/src/couch_quickjs/patches/04-test262-errors.patch
index d37155640..a393222d8 100644
--- a/src/couch_quickjs/patches/04-test262-errors.patch
+++ b/src/couch_quickjs/patches/04-test262-errors.patch
@@ -1,5 +1,5 @@
---- quickjs-master/test262_errors.txt  2025-08-25 12:20:58
-+++ quickjs/test262_errors.txt 2025-08-25 15:13:35
+--- quickjs-master/test262_errors.txt  2025-09-18 04:42:13
++++ quickjs/test262_errors.txt 2025-09-18 11:43:37
 @@ -7,6 +7,8 @@
  
test262/test/annexB/language/expressions/assignmenttargettype/cover-callexpression-and-asyncarrowhead.js:20:
 SyntaxError: invalid assignment left-hand side
  
test262/test/built-ins/Atomics/notify/retrieve-length-before-index-coercion-non-shared-detached.js:34:
 TypeError: ArrayBuffer is detached
diff --git a/src/couch_quickjs/quickjs/Changelog 
b/src/couch_quickjs/quickjs/Changelog
index b1443f5ad..8a32a92c1 100644
--- a/src/couch_quickjs/quickjs/Changelog
+++ b/src/couch_quickjs/quickjs/Changelog
@@ -1,3 +1,5 @@
+2025-09-13:
+
 - added JSON modules and import attributes
 - added JS_PrintValue() API
 - qjs: pretty print objects in print() and console.log()
@@ -12,6 +14,7 @@
   accept JSON5 modules
 - added JS_FreePropertyEnum() and JS_AtomToCStringLen() API
 - added Error.isError()
+- misc bug fixes
 
 2025-04-26:
 
diff --git a/src/couch_quickjs/quickjs/VERSION 
b/src/couch_quickjs/quickjs/VERSION
index c76e76d1f..433b8f85b 100644
--- a/src/couch_quickjs/quickjs/VERSION
+++ b/src/couch_quickjs/quickjs/VERSION
@@ -1 +1 @@
-2025-04-26
+2025-09-13
diff --git a/src/couch_quickjs/quickjs/qjsc.c b/src/couch_quickjs/quickjs/qjsc.c
index 49aa44985..e55ca61ce 100644
--- a/src/couch_quickjs/quickjs/qjsc.c
+++ b/src/couch_quickjs/quickjs/qjsc.c
@@ -362,6 +362,9 @@ static void compile_file(JSContext *ctx, FILE *fo,
         pstrcpy(c_name, sizeof(c_name), c_name1);
     } else {
         get_c_name(c_name, sizeof(c_name), filename);
+        if (namelist_find(&cname_list, c_name)) {
+            find_unique_cname(c_name, sizeof(c_name));
+        }
     }
     output_object_code(ctx, fo, obj, c_name, CNAME_TYPE_SCRIPT);
     JS_FreeValue(ctx, obj);
diff --git a/src/couch_quickjs/quickjs/quickjs.c 
b/src/couch_quickjs/quickjs/quickjs.c
index 2f1291702..b0f9d03ad 100644
--- a/src/couch_quickjs/quickjs/quickjs.c
+++ b/src/couch_quickjs/quickjs/quickjs.c
@@ -13002,73 +13002,6 @@ static JSValue JS_ToStringCheckObject(JSContext *ctx, 
JSValueConst val)
     return JS_ToString(ctx, val);
 }
 
-static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
-{
-    JSValue val;
-    JSString *p;
-    int i;
-    uint32_t c;
-    StringBuffer b_s, *b = &b_s;
-    char buf[16];
-
-    val = JS_ToStringCheckObject(ctx, val1);
-    if (JS_IsException(val))
-        return val;
-    p = JS_VALUE_GET_STRING(val);
-
-    if (string_buffer_init(ctx, b, p->len + 2))
-        goto fail;
-
-    if (string_buffer_putc8(b, '\"'))
-        goto fail;
-    for(i = 0; i < p->len; ) {
-        c = string_getc(p, &i);
-        switch(c) {
-        case '\t':
-            c = 't';
-            goto quote;
-        case '\r':
-            c = 'r';
-            goto quote;
-        case '\n':
-            c = 'n';
-            goto quote;
-        case '\b':
-            c = 'b';
-            goto quote;
-        case '\f':
-            c = 'f';
-            goto quote;
-        case '\"':
-        case '\\':
-        quote:
-            if (string_buffer_putc8(b, '\\'))
-                goto fail;
-            if (string_buffer_putc8(b, c))
-                goto fail;
-            break;
-        default:
-            if (c < 32 || is_surrogate(c)) {
-                snprintf(buf, sizeof(buf), "\\u%04x", c);
-                if (string_buffer_puts8(b, buf))
-                    goto fail;
-            } else {
-                if (string_buffer_putc(b, c))
-                    goto fail;
-            }
-            break;
-        }
-    }
-    if (string_buffer_putc8(b, '\"'))
-        goto fail;
-    JS_FreeValue(ctx, val);
-    return string_buffer_end(b);
- fail:
-    JS_FreeValue(ctx, val);
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
 #define JS_PRINT_MAX_DEPTH 8
 
 typedef struct {
@@ -13126,18 +13059,61 @@ static uint32_t js_string_get_length(JSValueConst val)
     }
 }
 
-static void js_dump_char(JSPrintValueState *s, int c, int sep)
+/* pretty print the first 'len' characters of 'p' */
+static void js_print_string1(JSPrintValueState *s, JSString *p, int len, int 
sep)
 {
-    if (c == sep || c == '\\') {
-        js_putc(s, '\\');
-        js_putc(s, c);
-    } else if (c >= ' ' && c <= 126) {
-        js_putc(s, c);
-    } else if (c == '\n') {
-        js_putc(s, '\\');
-        js_putc(s, 'n');
-    } else {
-        js_printf(s, "\\u%04x", c);
+    uint8_t buf[UTF8_CHAR_LEN_MAX];
+    int l, i, c, c1;
+
+    for(i = 0; i < len; i++) {
+        c = string_get(p, i);
+        switch(c) {
+        case '\t':
+            c = 't';
+            goto quote;
+        case '\r':
+            c = 'r';
+            goto quote;
+        case '\n':
+            c = 'n';
+            goto quote;
+        case '\b':
+            c = 'b';
+            goto quote;
+        case '\f':
+            c = 'f';
+            goto quote;
+        case '\\':
+        quote:
+            js_putc(s, '\\');
+            js_putc(s, c);
+            break;
+        default:
+            if (c == sep)
+                goto quote;
+            if (c >= 32 && c <= 126) {
+                js_putc(s, c);
+            } else if (c < 32 || 
+                       (c >= 0x7f && c <= 0x9f)) {
+            escape:
+                js_printf(s, "\\u%04x", c);
+            } else {
+                if (is_hi_surrogate(c)) {
+                    if ((i + 1) >= len)
+                        goto escape;
+                    c1 = string_get(p, i + 1);
+                    if (!is_lo_surrogate(c1))
+                        goto escape;
+                    i++;
+                    c = from_surrogate(c, c1);
+                } else if (is_lo_surrogate(c)) {
+                    goto escape;
+                }
+                l = unicode_to_utf8(buf, c);
+                s->write_func(s->write_opaque, (char *)buf, l);
+            }
+            break;
+        }
     }
 }
 
@@ -13146,12 +13122,10 @@ static void js_print_string_rec(JSPrintValueState *s, 
JSValueConst val,
 {
     if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
         JSString *p = JS_VALUE_GET_STRING(val);
-        uint32_t i, len;
+        uint32_t len;
         if (pos < s->options.max_string_length) {
             len = min_uint32(p->len, s->options.max_string_length - pos);
-            for(i = 0; i < len; i++) {
-                js_dump_char(s, string_get(p, i), sep);
-            }
+            js_print_string1(s, p, len, sep);
         }
     } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {
         JSStringRope *r = JS_VALUE_GET_PTR(val);
@@ -13224,9 +13198,7 @@ static void js_print_atom(JSPrintValueState *s, JSAtom 
atom)
             }
         } else {
             js_putc(s, '"');
-            for(i = 0; i < p->len; i++) {
-                js_dump_char(s, string_get(p, i), '\"');
-            }
+            js_print_string1(s, p, p->len, '\"');
             js_putc(s, '"');
         }
     }
@@ -16199,6 +16171,7 @@ static __exception int js_append_enumerate(JSContext 
*ctx, JSValue *sp)
     int is_array_iterator;
     JSValue *arrp;
     uint32_t i, count32, pos;
+    JSCFunctionType ft;
 
     if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) {
         JS_ThrowInternalError(ctx, "invalid index for append");
@@ -16216,8 +16189,8 @@ static __exception int js_append_enumerate(JSContext 
*ctx, JSValue *sp)
     iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator);
     if (JS_IsException(iterator))
         return -1;
-    is_array_iterator = JS_IsCFunction(ctx, iterator,
-                                       (JSCFunction *)js_create_array_iterator,
+    ft.generic_magic = js_create_array_iterator;
+    is_array_iterator = JS_IsCFunction(ctx, iterator, ft.generic,
                                        JS_ITERATOR_KIND_VALUE);
     JS_FreeValue(ctx, iterator);
 
@@ -16229,8 +16202,10 @@ static __exception int js_append_enumerate(JSContext 
*ctx, JSValue *sp)
         JS_FreeValue(ctx, enumobj);
         return -1;
     }
+
+    ft.iterator_next = js_array_iterator_next;
     if (is_array_iterator
-    &&  JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0)
+    &&  JS_IsCFunction(ctx, method, ft.generic, 0)
     &&  js_get_fast_array(ctx, sp[-1], &arrp, &count32)) {
         uint32_t len;
         if (js_get_length32(ctx, &len, sp[-1]))
@@ -34963,7 +34938,8 @@ static void free_function_bytecode(JSRuntime *rt, 
JSFunctionBytecode *b)
                JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
     }
 #endif
-    free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);
+    if (b->byte_code_buf)
+        free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);
 
     if (b->vardefs) {
         for(i = 0; i < b->arg_count + b->var_count; i++) {
@@ -40840,8 +40816,10 @@ done:
             goto exception;
         args[0] = ret;
         res = JS_Invoke(ctx, arr, JS_ATOM_set, 1, args);
-        if (check_exception_free(ctx, res))
+        if (check_exception_free(ctx, res)) {
+            JS_FreeValue(ctx, arr);
             goto exception;
+        }
         JS_FreeValue(ctx, ret);
         ret = arr;
     }
@@ -43870,12 +43848,6 @@ static JSValue js_string_trim(JSContext *ctx, 
JSValueConst this_val,
     return ret;
 }
 
-static JSValue js_string___quote(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    return JS_ToQuotedString(ctx, this_val);
-}
-
 /* return 0 if before the first char */
 static int string_prevc(JSString *p, int *pidx)
 {
@@ -44363,7 +44335,6 @@ static const JSCFunctionListEntry 
js_string_proto_funcs[] = {
     JS_ALIAS_DEF("trimLeft", "trimStart" ),
     JS_CFUNC_DEF("toString", 0, js_string_toString ),
     JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
-    JS_CFUNC_DEF("__quote", 1, js_string___quote ),
     JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
     JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
     JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ),
@@ -46678,10 +46649,72 @@ typedef struct JSONStringifyContext {
     StringBuffer *b;
 } JSONStringifyContext;
 
-static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) {
-    JSValue r = JS_ToQuotedString(ctx, val);
+static int JS_ToQuotedString(JSContext *ctx, StringBuffer *b, JSValueConst 
val1)
+{
+    JSValue val;
+    JSString *p;
+    int i;
+    uint32_t c;
+    char buf[16];
+
+    val = JS_ToStringCheckObject(ctx, val1);
+    if (JS_IsException(val))
+        return -1;
+    p = JS_VALUE_GET_STRING(val);
+
+    if (string_buffer_putc8(b, '\"'))
+        goto fail;
+    for(i = 0; i < p->len; ) {
+        c = string_getc(p, &i);
+        switch(c) {
+        case '\t':
+            c = 't';
+            goto quote;
+        case '\r':
+            c = 'r';
+            goto quote;
+        case '\n':
+            c = 'n';
+            goto quote;
+        case '\b':
+            c = 'b';
+            goto quote;
+        case '\f':
+            c = 'f';
+            goto quote;
+        case '\"':
+        case '\\':
+        quote:
+            if (string_buffer_putc8(b, '\\'))
+                goto fail;
+            if (string_buffer_putc8(b, c))
+                goto fail;
+            break;
+        default:
+            if (c < 32 || is_surrogate(c)) {
+                snprintf(buf, sizeof(buf), "\\u%04x", c);
+                if (string_buffer_puts8(b, buf))
+                    goto fail;
+            } else {
+                if (string_buffer_putc(b, c))
+                    goto fail;
+            }
+            break;
+        }
+    }
+    if (string_buffer_putc8(b, '\"'))
+        goto fail;
     JS_FreeValue(ctx, val);
-    return r;
+    return 0;
+ fail:
+    JS_FreeValue(ctx, val);
+    return -1;
+}
+
+static int JS_ToQuotedStringFree(JSContext *ctx, StringBuffer *b, JSValue val) 
{
+    int ret = JS_ToQuotedString(ctx, b, val);
+    JS_FreeValue(ctx, val);
+    return ret;
 }
 
 static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
@@ -46864,13 +46897,11 @@ static int js_json_to_str(JSContext *ctx, 
JSONStringifyContext *jsc,
                 if (!JS_IsUndefined(v)) {
                     if (has_content)
                         string_buffer_putc8(jsc->b, ',');
-                    prop = JS_ToQuotedStringFree(ctx, prop);
-                    if (JS_IsException(prop)) {
+                    string_buffer_concat_value(jsc->b, sep);
+                    if (JS_ToQuotedString(ctx, jsc->b, prop)) {
                         JS_FreeValue(ctx, v);
                         goto exception;
                     }
-                    string_buffer_concat_value(jsc->b, sep);
-                    string_buffer_concat_value(jsc->b, prop);
                     string_buffer_putc8(jsc->b, ':');
                     string_buffer_concat_value(jsc->b, sep1);
                     if (js_json_to_str(ctx, jsc, val, v, indent1))
@@ -46898,10 +46929,7 @@ static int js_json_to_str(JSContext *ctx, 
JSONStringifyContext *jsc,
     switch (JS_VALUE_GET_NORM_TAG(val)) {
     case JS_TAG_STRING:
     case JS_TAG_STRING_ROPE:
-        val = JS_ToQuotedStringFree(ctx, val);
-        if (JS_IsException(val))
-            goto exception;
-        goto concat_value;
+        return JS_ToQuotedStringFree(ctx, jsc->b, val);
     case JS_TAG_FLOAT64:
         if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
             val = JS_NULL;
@@ -50653,6 +50681,7 @@ void JS_AddIntrinsicPromise(JSContext *ctx)
 {
     JSRuntime *rt = ctx->rt;
     JSValue obj1;
+    JSCFunctionType ft;
 
     if (!JS_IsRegisteredClass(rt, JS_CLASS_PROMISE)) {
         init_class_range(rt, js_async_class_def, JS_CLASS_PROMISE,
@@ -50681,7 +50710,8 @@ void JS_AddIntrinsicPromise(JSContext *ctx)
 
     /* AsyncFunction */
     ctx->class_proto[JS_CLASS_ASYNC_FUNCTION] = JS_NewObjectProto(ctx, 
ctx->function_proto);
-    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
+    ft.generic_magic = js_function_constructor;
+    obj1 = JS_NewCFunction3(ctx, ft.generic,
                             "AsyncFunction", 1,
                             JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC,
                             ctx->function_ctor);
@@ -50717,7 +50747,8 @@ void JS_AddIntrinsicPromise(JSContext *ctx)
     /* AsyncGeneratorFunction */
     ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION] =
         JS_NewObjectProto(ctx, ctx->function_proto);
-    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
+    ft.generic_magic = js_function_constructor;
+    obj1 = JS_NewCFunction3(ctx, ft.generic,
                             "AsyncGeneratorFunction", 1,
                             JS_CFUNC_constructor_or_func_magic,
                             JS_FUNC_ASYNC_GENERATOR,
@@ -52441,6 +52472,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
     int i;
     JSValueConst obj, number_obj;
     JSValue obj1;
+    JSCFunctionType ft;
 
     ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0);
 
@@ -52481,7 +52513,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
     JS_SetPropertyFunctionList(ctx, obj1, js_error_funcs, 
countof(js_error_funcs));
 
     /* Used to squelch a -Wcast-function-type warning. */
-    JSCFunctionType ft = { .generic_magic = js_error_constructor };
+    ft.generic_magic = js_error_constructor;
     for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
         JSValue func_obj;
         int n_args;
@@ -52624,7 +52656,8 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
                                countof(js_generator_proto_funcs));
 
     ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION] = JS_NewObjectProto(ctx, 
ctx->function_proto);
-    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
+    ft.generic_magic = js_function_constructor;
+    obj1 = JS_NewCFunction3(ctx, ft.generic,
                             "GeneratorFunction", 1,
                             JS_CFUNC_constructor_or_func_magic, 
JS_FUNC_GENERATOR,
                             ctx->function_ctor);
diff --git a/src/couch_quickjs/quickjs/quickjs.h 
b/src/couch_quickjs/quickjs/quickjs.h
index 4570c6d3e..c8cd14944 100644
--- a/src/couch_quickjs/quickjs/quickjs.h
+++ b/src/couch_quickjs/quickjs/quickjs.h
@@ -1049,7 +1049,9 @@ static inline JSValue JS_NewCFunctionMagic(JSContext 
*ctx, JSCFunctionMagic *fun
                                            const char *name,
                                            int length, JSCFunctionEnum cproto, 
int magic)
 {
-    return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, 
magic);
+    /* Used to squelch a -Wcast-function-type warning. */
+    JSCFunctionType ft = { .generic_magic = func };
+    return JS_NewCFunction2(ctx, ft.generic, name, length, cproto, magic);
 }
 void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
                        JSValueConst proto);
diff --git a/src/couch_quickjs/quickjs/run-test262.c 
b/src/couch_quickjs/quickjs/run-test262.c
index ef16025ae..100ed134a 100644
--- a/src/couch_quickjs/quickjs/run-test262.c
+++ b/src/couch_quickjs/quickjs/run-test262.c
@@ -78,6 +78,7 @@ char *harness_dir;
 char *harness_exclude;
 char *harness_features;
 char *harness_skip_features;
+int *harness_skip_features_count;
 char *error_filename;
 char *error_file;
 FILE *error_out;
@@ -1736,10 +1737,13 @@ int run_test(const char *filename, int index)
             p = find_tag(desc, "features:", &state);
             if (p) {
                 while ((option = get_option(&p, &state)) != NULL) {
+                    char *p1;
                     if (find_word(harness_features, option)) {
                         /* feature is enabled */
-                    } else if (find_word(harness_skip_features, option)) {
+                    } else if ((p1 = find_word(harness_skip_features, option)) 
!= NULL) {
                         /* skip disabled feature */
+                        if (harness_skip_features_count)
+                            harness_skip_features_count[p1 - 
harness_skip_features]++;
                         skip |= 1;
                     } else {
                         /* feature is not listed: skip and warn */
@@ -2072,6 +2076,7 @@ int main(int argc, char **argv)
     const char *ignore = "";
     BOOL is_test262_harness = FALSE;
     BOOL is_module = FALSE;
+    BOOL count_skipped_features = FALSE;
     clock_t clocks;
 
 #if !defined(_WIN32)
@@ -2139,6 +2144,8 @@ int main(int argc, char **argv)
             is_test262_harness = TRUE;
         } else if (str_equal(arg, "--module")) {
             is_module = TRUE;
+        } else if (str_equal(arg, "--count_skipped_features")) {
+            count_skipped_features = TRUE;
         } else {
             fatal(1, "unknown option: %s", arg);
             break;
@@ -2173,6 +2180,14 @@ int main(int argc, char **argv)
 
     clocks = clock();
 
+    if (count_skipped_features) {
+        /* not storage efficient but it is simple */
+        size_t size;
+        size = sizeof(harness_skip_features_count[0]) * 
strlen(harness_skip_features);
+        harness_skip_features_count = malloc(size);
+        memset(harness_skip_features_count, 0, size);
+    }
+    
     if (is_dir_list) {
         if (optind < argc && !isdigit((unsigned char)argv[optind][0])) {
             filename = argv[optind++];
@@ -2223,6 +2238,30 @@ int main(int argc, char **argv)
         printf("\n");
     }
 
+    if (count_skipped_features) {
+        size_t i, n, len = strlen(harness_skip_features);
+        BOOL disp = FALSE;
+        int c;
+        for(i = 0; i < len; i++) {
+            if (harness_skip_features_count[i] != 0) {
+                if (!disp) {
+                    disp = TRUE;
+                    printf("%-30s %7s\n", "SKIPPED FEATURE", "COUNT");
+                }
+                for(n = 0; n < 30; n++) {
+                    c = harness_skip_features[i + n];
+                    if (is_word_sep(c))
+                        break;
+                    putchar(c);
+                }
+                for(; n < 30; n++)
+                    putchar(' ');
+                printf(" %7d\n", harness_skip_features_count[i]);
+            }
+        }
+        printf("\n");
+    }
+    
     if (is_dir_list) {
         fprintf(stderr, "Result: %d/%d error%s",
                 test_failed, test_count, test_count != 1 ? "s" : "");
@@ -2252,6 +2291,8 @@ int main(int argc, char **argv)
     namelist_free(&exclude_list);
     namelist_free(&exclude_dir_list);
     free(harness_dir);
+    free(harness_skip_features);
+    free(harness_skip_features_count);
     free(harness_features);
     free(harness_exclude);
     free(error_file);

Reply via email to