This is an automated email from the ASF dual-hosted git repository.
vatamane pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb.git
The following commit(s) were added to refs/heads/main by this push:
new 831849ca4 Update QuickJS
831849ca4 is described below
commit 831849ca4e94b0865aa0a0c3cd68a0f6e22290a0
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);