This is an automated email from the ASF dual-hosted git repository. vatamane pushed a commit to branch jenkins-next-quickjs-update in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit dd1c4202fb5cdd53297ffd9b7d04ca2614321e4a Author: Nick Vatamaniuc <[email protected]> AuthorDate: Mon Aug 25 15:39:02 2025 -0400 QuickJS Update * TypedArray.prototype.subarray: fixed the step at which '[[ByteOffset]]' is read https://github.com/bellard/quickjs/commit/c942978927a2a806517598a22a07c50766b3e125 * Fixed buffer overflow in `js_bigint_from_string()` https://github.com/bellard/quickjs/commit/e1c18befb8ef661d9ee8a34ebc54e545a0214df9 * Fixed crash in OP_add_loc if the variable is modified in `JS_ToPrimitiveFree()` https://github.com/bellard/quickjs/commit/1168c215d1daf2765a24d950079b1d5538305417 * Fixed buffer overflow in `js_bigint_to_string1()` https://github.com/bellard/quickjs/commit/9ce544289fe86acdb8fb33e6a425da151438be05 * Fixed buffer overflow in `TypedArray.prototype.lastIndexOf()` https://github.com/bellard/quickjs/commit/c927eca49a326326181a5db12627ffb48f191fe2 * Avoid side effects in `JS_PrintValue()` which may lead to crashes in `print()` and `js_std_promise_rejection_check()` https://github.com/bellard/quickjs/commit/4e0d0b7f807816097cd4e15996c5296984dc531b * Limit function and regexp bytecode to 1G to avoid buffer overflows (the bytecode generators assume that bytecode offsets can fit a 32 bit signed integer https://github.com/bellard/quickjs/commit/d9ec8f102eb211f0b230a5ec3bf5da59f333e697 * Adjust lastIndex to leading surrogate when inside a surrogate pair in unicode RegExp https://github.com/bellard/quickjs/commit/a4ac84d993128ec4cfe2cadcbb0893a2c2565988 --- .../patches/01-spidermonkey-185-mode.patch | 6 +- .../patches/02-test262-makefile.patch | 8 +- src/couch_quickjs/patches/03-test262-yield.patch | 4 +- src/couch_quickjs/patches/04-test262-errors.patch | 8 +- src/couch_quickjs/quickjs/Makefile | 4 +- src/couch_quickjs/quickjs/libregexp.c | 25 +- src/couch_quickjs/quickjs/quickjs-libc.c | 14 +- src/couch_quickjs/quickjs/quickjs.c | 428 ++++++++++++++------- src/couch_quickjs/quickjs/run-test262.c | 11 +- src/couch_quickjs/quickjs/test262.conf | 2 + src/couch_quickjs/quickjs/test262_errors.txt | 20 +- src/couch_quickjs/quickjs/tests/test262.patch | 23 +- 12 files changed, 370 insertions(+), 183 deletions(-) diff --git a/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch b/src/couch_quickjs/patches/01-spidermonkey-185-mode.patch index d4a85a5a0..20ac3172e 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-06-14 05:51:48 -+++ quickjs/quickjs.c 2025-06-20 13:56:52 -@@ -30599,10 +30599,24 @@ +--- quickjs-master/quickjs.c 2025-08-25 12:20:58 ++++ quickjs/quickjs.c 2025-08-25 15:10:50 +@@ -30776,10 +30776,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 1bfc17640..a4fb9b4b1 100644 --- a/src/couch_quickjs/patches/02-test262-makefile.patch +++ b/src/couch_quickjs/patches/02-test262-makefile.patch @@ -1,13 +1,13 @@ ---- quickjs-master/Makefile 2025-06-14 05:51:48 -+++ quickjs/Makefile 2025-06-20 18:03:41 +--- quickjs-master/Makefile 2025-08-25 12:20:58 ++++ quickjs/Makefile 2025-08-25 15:27:47 @@ -53,6 +53,10 @@ #CONFIG_MSAN=y # use UB sanitizer #CONFIG_UBSAN=y + +# TEST262 bootstrap config: commit id and shallow "since" parameter -+TEST262_COMMIT?=3316c0aaf676d657f5a6b33364fa7e579c78ac7f -+TEST262_SINCE?=2025-05-21 ++TEST262_COMMIT?=04eaeb99080ceb60d7b86ea0c4bed6355ef4cdcb ++TEST262_SINCE?=2025-08-20 OBJDIR=.obj diff --git a/src/couch_quickjs/patches/03-test262-yield.patch b/src/couch_quickjs/patches/03-test262-yield.patch index e4dc4c5be..419e609c3 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-06-14 05:51:48 -+++ quickjs/tests/test262.patch 2025-06-20 18:03:41 +--- quickjs-master/tests/test262.patch 2025-08-25 12:20:58 ++++ quickjs/tests/test262.patch 2025-08-25 15:10:50 @@ -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 3de2591e6..d37155640 100644 --- a/src/couch_quickjs/patches/04-test262-errors.patch +++ b/src/couch_quickjs/patches/04-test262-errors.patch @@ -1,9 +1,9 @@ ---- quickjs-master/test262_errors.txt 2025-06-14 05:51:48 -+++ quickjs/test262_errors.txt 2025-06-20 18:03:41 -@@ -1,6 +1,8 @@ +--- quickjs-master/test262_errors.txt 2025-08-25 12:20:58 ++++ quickjs/test262_errors.txt 2025-08-25 15:13:35 +@@ -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 test262/test/built-ins/Atomics/notify/retrieve-length-before-index-coercion-non-shared-detached.js:34: strict mode: TypeError: ArrayBuffer is detached - test262/test/language/module-code/top-level-await/module-graphs-does-not-hang.js:10: TypeError: $DONE() not called +test262/test/language/statements/expression/S12.4_A1.js:15: unexpected error type: Test262: This statement should not be evaluated. +test262/test/language/statements/expression/S12.4_A1.js:15: strict mode: unexpected error type: Test262: This statement should not be evaluated. test262/test/staging/sm/Date/UTC-convert-all-arguments.js:75: Test262Error: index 1: expected 42, got Error: didn't throw Expected SameValue(«Error: didn't throw», «42») to be true diff --git a/src/couch_quickjs/quickjs/Makefile b/src/couch_quickjs/quickjs/Makefile index fd74c7be2..6ee5d4367 100644 --- a/src/couch_quickjs/quickjs/Makefile +++ b/src/couch_quickjs/quickjs/Makefile @@ -55,8 +55,8 @@ PREFIX?=/usr/local #CONFIG_UBSAN=y # TEST262 bootstrap config: commit id and shallow "since" parameter -TEST262_COMMIT?=3316c0aaf676d657f5a6b33364fa7e579c78ac7f -TEST262_SINCE?=2025-05-21 +TEST262_COMMIT?=04eaeb99080ceb60d7b86ea0c4bed6355ef4cdcb +TEST262_SINCE?=2025-08-20 OBJDIR=.obj diff --git a/src/couch_quickjs/quickjs/libregexp.c b/src/couch_quickjs/quickjs/libregexp.c index 2b33c8695..0cf9a1261 100644 --- a/src/couch_quickjs/quickjs/libregexp.c +++ b/src/couch_quickjs/quickjs/libregexp.c @@ -2433,6 +2433,17 @@ static int compute_stack_size(const uint8_t *bc_buf, int bc_buf_len) return stack_size_max; } +static void *lre_bytecode_realloc(void *opaque, void *ptr, size_t size) +{ + if (size > (INT32_MAX / 2)) { + /* the bytecode cannot be larger than 2G. Leave some slack to + avoid some overflows. */ + return NULL; + } else { + return lre_realloc(opaque, ptr, size); + } +} + /* 'buf' must be a zero terminated UTF-8 string of length buf_len. Return NULL if error and allocate an error message in *perror_msg, otherwise the compiled bytecode and its length in plen. @@ -2461,7 +2472,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, s->total_capture_count = -1; s->has_named_captures = -1; - dbuf_init2(&s->byte_code, opaque, lre_realloc); + dbuf_init2(&s->byte_code, opaque, lre_bytecode_realloc); dbuf_init2(&s->group_names, opaque, lre_realloc); dbuf_put_u16(&s->byte_code, re_flags); /* first element is the flags */ @@ -3152,6 +3163,7 @@ int lre_exec(uint8_t **capture, REExecContext s_s, *s = &s_s; int re_flags, i, alloca_size, ret; StackInt *stack_buf; + const uint8_t *cptr; re_flags = lre_get_flags(bc_buf); s->is_unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0; @@ -3176,8 +3188,17 @@ int lre_exec(uint8_t **capture, capture[i] = NULL; alloca_size = s->stack_size_max * sizeof(stack_buf[0]); stack_buf = alloca(alloca_size); + + cptr = cbuf + (cindex << cbuf_type); + if (0 < cindex && cindex < clen && s->cbuf_type == 2) { + const uint16_t *p = (const uint16_t *)cptr; + if (is_lo_surrogate(*p) && is_hi_surrogate(p[-1])) { + cptr = (const uint8_t *)(p - 1); + } + } + ret = lre_exec_backtrack(s, capture, stack_buf, 0, bc_buf + RE_HEADER_LEN, - cbuf + (cindex << cbuf_type), FALSE); + cptr, FALSE); lre_realloc(s->opaque, s->state_stack, 0); return ret; } diff --git a/src/couch_quickjs/quickjs/quickjs-libc.c b/src/couch_quickjs/quickjs/quickjs-libc.c index 10a7d00cc..54a7a15bd 100644 --- a/src/couch_quickjs/quickjs/quickjs-libc.c +++ b/src/couch_quickjs/quickjs/quickjs-libc.c @@ -4230,17 +4230,15 @@ static void js_std_promise_rejection_check(JSContext *ctx) /* main loop which calls the user JS callbacks */ void js_std_loop(JSContext *ctx) { - JSContext *ctx1; int err; for(;;) { /* execute the pending jobs */ for(;;) { - err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL); if (err <= 0) { - if (err < 0) { - js_std_dump_error(ctx1); - } + if (err < 0) + js_std_dump_error(ctx); break; } } @@ -4271,11 +4269,10 @@ JSValue js_std_await(JSContext *ctx, JSValue obj) JS_FreeValue(ctx, obj); break; } else if (state == JS_PROMISE_PENDING) { - JSContext *ctx1; int err; - err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL); if (err < 0) { - js_std_dump_error(ctx1); + js_std_dump_error(ctx); } if (err == 0) { js_std_promise_rejection_check(ctx); @@ -4303,6 +4300,7 @@ void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { js_module_set_import_meta(ctx, obj, FALSE, FALSE); } + JS_FreeValue(ctx, obj); } else { if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { if (JS_ResolveModule(ctx, obj) < 0) { diff --git a/src/couch_quickjs/quickjs/quickjs.c b/src/couch_quickjs/quickjs/quickjs.c index 10d28d6f1..2f1291702 100644 --- a/src/couch_quickjs/quickjs/quickjs.c +++ b/src/couch_quickjs/quickjs/quickjs.c @@ -103,6 +103,7 @@ //#define DUMP_ATOMS /* dump atoms in JS_FreeContext */ //#define DUMP_SHAPES /* dump shapes in JS_FreeContext */ //#define DUMP_MODULE_RESOLVE +//#define DUMP_MODULE_EXEC //#define DUMP_PROMISE //#define DUMP_READ_OBJECT //#define DUMP_ROPE_REBALANCE @@ -340,6 +341,7 @@ typedef enum { JS_GC_OBJ_TYPE_VAR_REF, JS_GC_OBJ_TYPE_ASYNC_FUNCTION, JS_GC_OBJ_TYPE_JS_CONTEXT, + JS_GC_OBJ_TYPE_MODULE, } JSGCObjectTypeEnum; /* header for GC objects. GC objects are C data structures with a @@ -804,7 +806,7 @@ typedef enum { } JSModuleStatus; struct JSModuleDef { - JSRefCountHeader header; /* must come first, 32-bit */ + JSGCObjectHeader header; /* must come first */ JSAtom module_name; struct list_head link; @@ -839,7 +841,8 @@ struct JSModuleDef { int async_parent_modules_count; int async_parent_modules_size; int pending_async_dependencies; - BOOL async_evaluation; + BOOL async_evaluation; /* true: async_evaluation_timestamp corresponds to [[AsyncEvaluationOrder]] + false: [[AsyncEvaluationOrder]] is UNSET or DONE */ int64_t async_evaluation_timestamp; JSModuleDef *cycle_root; JSValue promise; /* corresponds to spec field: capability */ @@ -855,7 +858,7 @@ struct JSModuleDef { typedef struct JSJobEntry { struct list_head link; - JSContext *ctx; + JSContext *realm; JSJobFunc *job_func; int argc; JSValue argv[0]; @@ -1220,7 +1223,7 @@ static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, const char *input, size_t input_len, const char *filename, int flags, int scope_idx); -static void js_free_module_def(JSContext *ctx, JSModuleDef *m); +static void js_free_module_def(JSRuntime *rt, JSModuleDef *m); static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, JS_MarkFunc *mark_func); static JSValue js_import_meta(JSContext *ctx); @@ -1467,6 +1470,23 @@ static inline void js_dbuf_init(JSContext *ctx, DynBuf *s) dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt); } +static void *js_realloc_bytecode_rt(void *opaque, void *ptr, size_t size) +{ + JSRuntime *rt = opaque; + if (size > (INT32_MAX / 2)) { + /* the bytecode cannot be larger than 2G. Leave some slack to + avoid some overflows. */ + return NULL; + } else { + return rt->mf.js_realloc(&rt->malloc_state, ptr, size); + } +} + +static inline void js_dbuf_bytecode_init(JSContext *ctx, DynBuf *s) +{ + dbuf_init2(s, ctx->rt, js_realloc_bytecode_rt); +} + static inline int is_digit(int c) { return c >= '0' && c <= '9'; } @@ -1780,7 +1800,7 @@ int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue)); if (!e) return -1; - e->ctx = ctx; + e->realm = JS_DupContext(ctx); e->job_func = job_func; e->argc = argc; for(i = 0; i < argc; i++) { @@ -1796,7 +1816,10 @@ BOOL JS_IsJobPending(JSRuntime *rt) } /* return < 0 if exception, 0 if no job pending, 1 if a job was - executed successfully. the context of the job is stored in '*pctx' */ + executed successfully. The context of the job is stored in '*pctx' + if pctx != NULL. It may be NULL if the context was already + destroyed or if no job was pending. The 'pctx' parameter is now + absolete. */ int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx) { JSContext *ctx; @@ -1805,15 +1828,16 @@ int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx) int i, ret; if (list_empty(&rt->job_list)) { - *pctx = NULL; + if (pctx) + *pctx = NULL; return 0; } /* get the first pending job and execute it */ e = list_entry(rt->job_list.next, JSJobEntry, link); list_del(&e->link); - ctx = e->ctx; - res = e->job_func(e->ctx, e->argc, (JSValueConst *)e->argv); + ctx = e->realm; + res = e->job_func(ctx, e->argc, (JSValueConst *)e->argv); for(i = 0; i < e->argc; i++) JS_FreeValue(ctx, e->argv[i]); if (JS_IsException(res)) @@ -1822,7 +1846,13 @@ int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx) ret = 1; JS_FreeValue(ctx, res); js_free(ctx, e); - *pctx = ctx; + if (pctx) { + if (ctx->header.ref_count > 1) + *pctx = ctx; + else + *pctx = NULL; + } + JS_FreeContext(ctx); return ret; } @@ -1903,6 +1933,7 @@ void JS_FreeRuntime(JSRuntime *rt) JSJobEntry *e = list_entry(el, JSJobEntry, link); for(i = 0; i < e->argc; i++) JS_FreeValueRT(rt, e->argv[i]); + JS_FreeContext(e->realm); js_free_rt(rt, e); } init_list_head(&rt->job_list); @@ -2178,7 +2209,13 @@ static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag) JSModuleDef *m = list_entry(el, JSModuleDef, link); if (flag == JS_FREE_MODULE_ALL || (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) { - js_free_module_def(ctx, m); + /* warning: the module may be referenced elsewhere. It + could be simpler to use an array instead of a list for + 'ctx->loaded_modules' */ + list_del(&m->link); + m->link.prev = NULL; + m->link.next = NULL; + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); } } } @@ -2196,11 +2233,9 @@ static void JS_MarkContext(JSRuntime *rt, JSContext *ctx, int i; struct list_head *el; - /* modules are not seen by the GC, so we directly mark the objects - referenced by each module */ list_for_each(el, &ctx->loaded_modules) { JSModuleDef *m = list_entry(el, JSModuleDef, link); - js_mark_module_def(rt, m, mark_func); + JS_MarkValue(rt, JS_MKPTR(JS_TAG_MODULE, m), mark_func); } JS_MarkValue(rt, ctx->global_obj, mark_func); @@ -5781,6 +5816,9 @@ static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp) case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: __async_func_free(rt, (JSAsyncFunctionState *)gp); break; + case JS_GC_OBJ_TYPE_MODULE: + js_free_module_def(rt, (JSModuleDef *)gp); + break; default: abort(); } @@ -5845,6 +5883,7 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v) break; case JS_TAG_OBJECT: case JS_TAG_FUNCTION_BYTECODE: + case JS_TAG_MODULE: { JSGCObjectHeader *p = JS_VALUE_GET_PTR(v); if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) { @@ -5857,9 +5896,6 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v) } } break; - case JS_TAG_MODULE: - abort(); /* never freed here */ - break; case JS_TAG_BIG_INT: { JSBigInt *p = JS_VALUE_GET_PTR(v); @@ -5933,6 +5969,7 @@ void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) switch(JS_VALUE_GET_TAG(val)) { case JS_TAG_OBJECT: case JS_TAG_FUNCTION_BYTECODE: + case JS_TAG_MODULE: mark_func(rt, JS_VALUE_GET_PTR(val)); break; default: @@ -6045,6 +6082,12 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, JS_MarkContext(rt, ctx, mark_func); } break; + case JS_GC_OBJ_TYPE_MODULE: + { + JSModuleDef *m = (JSModuleDef *)gp; + js_mark_module_def(rt, m, mark_func); + } + break; default: abort(); } @@ -6141,6 +6184,7 @@ static void gc_free_cycles(JSRuntime *rt) case JS_GC_OBJ_TYPE_JS_OBJECT: case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: + case JS_GC_OBJ_TYPE_MODULE: #ifdef DUMP_GC_FREE if (!header_done) { printf("Freeing cycles:\n"); @@ -6163,7 +6207,8 @@ static void gc_free_cycles(JSRuntime *rt) p = list_entry(el, JSGCObjectHeader, link); assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT || p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE || - p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION); + p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION || + p->gc_obj_type == JS_GC_OBJ_TYPE_MODULE); if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT && ((JSObject *)p)->weakref_count != 0) { /* keep the object because there are weak references to it */ @@ -6849,20 +6894,30 @@ static int find_line_num(JSContext *ctx, JSFunctionBytecode *b, return 0; } -/* in order to avoid executing arbitrary code during the stack trace - generation, we only look at simple 'name' properties containing a - string. */ -static const char *get_func_name(JSContext *ctx, JSValueConst func) +/* return a string property without executing arbitrary JS code (used + when dumping the stack trace or in debug print). */ +static const char *get_prop_string(JSContext *ctx, JSValueConst obj, JSAtom prop) { + JSObject *p; JSProperty *pr; JSShapeProperty *prs; JSValueConst val; - if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT) - return NULL; - prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name); - if (!prs) + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) return NULL; + p = JS_VALUE_GET_OBJ(obj); + prs = find_own_property(&pr, p, prop); + if (!prs) { + /* we look at one level in the prototype to handle the 'name' + field of the Error objects */ + p = p->shape->proto; + if (!p) + return NULL; + prs = find_own_property(&pr, p, prop); + if (!prs) + return NULL; + } + if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL) return NULL; val = pr->u.value; @@ -6915,7 +6970,7 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj, backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL; continue; } - func_name_str = get_func_name(ctx, sf->cur_func); + func_name_str = get_prop_string(ctx, sf->cur_func, JS_ATOM_name); if (!func_name_str || func_name_str[0] == '\0') str1 = "<anonymous>"; else @@ -11717,6 +11772,7 @@ static JSBigInt *js_bigint_from_string(JSContext *ctx, const char *str, int radix) { const char *p = str; + size_t n_digits1; int is_neg, n_digits, n_limbs, len, log2_radix, n_bits, i; JSBigInt *r; js_limb_t v, c, h; @@ -11728,10 +11784,16 @@ static JSBigInt *js_bigint_from_string(JSContext *ctx, } while (*p == '0') p++; - n_digits = strlen(p); + n_digits1 = strlen(p); + /* the real check for overflox is done js_bigint_new(). Here + we just avoid integer overflow */ + if (n_digits1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS) { + JS_ThrowRangeError(ctx, "BigInt is too large to allocate"); + return NULL; + } + n_digits = n_digits1; log2_radix = 32 - clz32(radix - 1); /* ceil(log2(radix)) */ /* compute the maximum number of limbs */ - /* XXX: overflow */ if (radix == 10) { n_bits = (n_digits * 27 + 7) / 8; /* >= ceil(n_digits * log2(10)) */ } else { @@ -11962,11 +12024,10 @@ static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix) bit_pos = i * log2_radix; pos = bit_pos / JS_LIMB_BITS; shift = bit_pos % JS_LIMB_BITS; - if (likely((shift + log2_radix) <= JS_LIMB_BITS)) { - c = r->tab[pos] >> shift; - } else { - c = (r->tab[pos] >> shift) | - (r->tab[pos + 1] << (JS_LIMB_BITS - shift)); + c = r->tab[pos] >> shift; + if ((shift + log2_radix) > JS_LIMB_BITS && + (pos + 1) < r->len) { + c |= r->tab[pos + 1] << (JS_LIMB_BITS - shift); } c &= (radix - 1); *--q = digits[c]; @@ -12179,8 +12240,10 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, if (has_legacy_octal || is_float) goto fail; r = js_bigint_from_string(ctx, buf, radix); - if (!r) - goto mem_error; + if (!r) { + val = JS_EXCEPTION; + goto done; + } val = JS_CompactBigInt(ctx, r); } break; @@ -13118,24 +13181,17 @@ static void js_print_string(JSPrintValueState *s, JSValueConst val) } } -static void js_print_raw_string2(JSPrintValueState *s, JSValueConst val, BOOL remove_last_lf) +static void js_print_raw_string(JSPrintValueState *s, JSValueConst val) { const char *cstr; size_t len; cstr = JS_ToCStringLen(s->ctx, &len, val); if (cstr) { - if (remove_last_lf && len > 0 && cstr[len - 1] == '\n') - len--; s->write_func(s->write_opaque, cstr, len); JS_FreeCString(s->ctx, cstr); } } -static void js_print_raw_string(JSPrintValueState *s, JSValueConst val) -{ - js_print_raw_string2(s, val, FALSE); -} - static BOOL is_ascii_ident(const JSString *p) { int i, c; @@ -13221,6 +13277,104 @@ static void js_print_more_items(JSPrintValueState *s, int *pcomma_state, js_printf(s, "... %u more item%s", n, n > 1 ? "s" : ""); } +/* similar to js_regexp_toString() but without side effect */ +static void js_print_regexp(JSPrintValueState *s, JSObject *p1) +{ + JSRegExp *re = &p1->u.regexp; + JSString *p; + int i, n, c, c2, bra, flags; + static const char regexp_flags[] = { 'g', 'i', 'm', 's', 'u', 'y', 'd', 'v' }; + + p = re->pattern; + js_putc(s, '/'); + if (p->len == 0) { + js_puts(s, "(?:)"); + } else { + bra = 0; + for (i = 0, n = p->len; i < n;) { + c2 = -1; + switch (c = string_get(p, i++)) { + case '\\': + if (i < n) + c2 = string_get(p, i++); + break; + case ']': + bra = 0; + break; + case '[': + if (!bra) { + if (i < n && string_get(p, i) == ']') + c2 = string_get(p, i++); + bra = 1; + } + break; + case '\n': + c = '\\'; + c2 = 'n'; + break; + case '\r': + c = '\\'; + c2 = 'r'; + break; + case '/': + if (!bra) { + c = '\\'; + c2 = '/'; + } + break; + } + js_putc(s, c); + if (c2 >= 0) + js_putc(s, c2); + } + } + js_putc(s, '/'); + + flags = lre_get_flags(re->bytecode->u.str8); + for(i = 0; i < countof(regexp_flags); i++) { + if ((flags >> i) & 1) { + js_putc(s, regexp_flags[i]); + } + } +} + +/* similar to js_error_toString() but without side effect */ +static void js_print_error(JSPrintValueState *s, JSObject *p) +{ + const char *str; + size_t len; + + str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_name); + if (!str) { + js_puts(s, "Error"); + } else { + js_puts(s, str); + JS_FreeCString(s->ctx, str); + } + + str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_message); + if (str && str[0] != '\0') { + js_puts(s, ": "); + js_puts(s, str); + } + JS_FreeCString(s->ctx, str); + + /* dump the stack if present */ + str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_stack); + if (str) { + js_putc(s, '\n'); + + /* XXX: should remove the last '\n' in stack as + v8. SpiderMonkey does not do it */ + len = strlen(str); + if (len > 0 && str[len - 1] == '\n') + len--; + s->write_func(s->write_opaque, str, len); + + JS_FreeCString(s->ctx, str); + } +} + static void js_print_object(JSPrintValueState *s, JSObject *p) { JSRuntime *rt = s->rt; @@ -13316,7 +13470,7 @@ static void js_print_object(JSPrintValueState *s, JSObject *p) if (!s->options.raw_dump && s->ctx) { const char *func_name_str; js_putc(s, ' '); - func_name_str = get_func_name(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + func_name_str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_name); if (!func_name_str || func_name_str[0] == '\0') js_puts(s, "(anonymous)"); else @@ -13350,35 +13504,19 @@ static void js_print_object(JSPrintValueState *s, JSObject *p) } if (i < ms->record_count) js_print_more_items(s, &comma_state, ms->record_count - i); - } else if (p->class_id == JS_CLASS_REGEXP && s->ctx && !s->options.raw_dump) { - JSValue str = js_regexp_toString(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL); - if (JS_IsException(str)) - goto default_obj; - js_print_raw_string(s, str); - JS_FreeValueRT(s->rt, str); + } else if (p->class_id == JS_CLASS_REGEXP && s->ctx) { + js_print_regexp(s, p); comma_state = 2; - } else if (p->class_id == JS_CLASS_DATE && s->ctx && !s->options.raw_dump) { + } else if (p->class_id == JS_CLASS_DATE && s->ctx) { + /* get_date_string() has no side effect */ JSValue str = get_date_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL, 0x23); /* toISOString() */ if (JS_IsException(str)) goto default_obj; js_print_raw_string(s, str); JS_FreeValueRT(s->rt, str); comma_state = 2; - } else if (p->class_id == JS_CLASS_ERROR && s->ctx && !s->options.raw_dump) { - JSValue str = js_error_toString(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL); - if (JS_IsException(str)) - goto default_obj; - js_print_raw_string(s, str); - JS_FreeValueRT(s->rt, str); - /* dump the stack if present */ - str = JS_GetProperty(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_stack); - if (JS_IsString(str)) { - js_putc(s, '\n'); - /* XXX: should remove the last '\n' in stack as - v8. SpiderMonkey does not do it */ - js_print_raw_string2(s, str, TRUE); - } - JS_FreeValueRT(s->rt, str); + } else if (p->class_id == JS_CLASS_ERROR && s->ctx) { + js_print_error(s, p); comma_state = 2; } else { default_obj: @@ -13745,6 +13883,9 @@ static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p) case JS_GC_OBJ_TYPE_JS_CONTEXT: printf("[js_context]"); break; + case JS_GC_OBJ_TYPE_MODULE: + printf("[module]"); + break; default: printf("[unknown %d]", p->gc_obj_type); break; @@ -18606,12 +18747,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, *pv = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(*pv) + JS_VALUE_GET_FLOAT64(op2)); sp--; - } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) { + } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING && + JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) { sp--; sf->cur_pc = pc; - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); - if (JS_IsException(op2)) - goto exception; if (JS_ConcatStringInPlace(ctx, JS_VALUE_GET_STRING(*pv), op2)) { JS_FreeValue(ctx, op2); } else { @@ -28214,7 +28353,7 @@ fail: return -1; } -/* 'name' is freed */ +/* 'name' is freed. The module is referenced by 'ctx->loaded_modules' */ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name) { JSModuleDef *m; @@ -28224,6 +28363,7 @@ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name) return NULL; } m->header.ref_count = 1; + add_gc_object(ctx->rt, &m->header, JS_GC_OBJ_TYPE_MODULE); m->module_name = name; m->module_ns = JS_UNDEFINED; m->func_obj = JS_UNDEFINED; @@ -28265,47 +28405,56 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, JS_MarkValue(rt, m->private_value, mark_func); } -static void js_free_module_def(JSContext *ctx, JSModuleDef *m) +static void js_free_module_def(JSRuntime *rt, JSModuleDef *m) { int i; - JS_FreeAtom(ctx, m->module_name); + JS_FreeAtomRT(rt, m->module_name); for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; - JS_FreeAtom(ctx, rme->module_name); - JS_FreeValue(ctx, rme->attributes); + JS_FreeAtomRT(rt, rme->module_name); + JS_FreeValueRT(rt, rme->attributes); } - js_free(ctx, m->req_module_entries); + js_free_rt(rt, m->req_module_entries); for(i = 0; i < m->export_entries_count; i++) { JSExportEntry *me = &m->export_entries[i]; if (me->export_type == JS_EXPORT_TYPE_LOCAL) - free_var_ref(ctx->rt, me->u.local.var_ref); - JS_FreeAtom(ctx, me->export_name); - JS_FreeAtom(ctx, me->local_name); + free_var_ref(rt, me->u.local.var_ref); + JS_FreeAtomRT(rt, me->export_name); + JS_FreeAtomRT(rt, me->local_name); } - js_free(ctx, m->export_entries); + js_free_rt(rt, m->export_entries); - js_free(ctx, m->star_export_entries); + js_free_rt(rt, m->star_export_entries); for(i = 0; i < m->import_entries_count; i++) { JSImportEntry *mi = &m->import_entries[i]; - JS_FreeAtom(ctx, mi->import_name); + JS_FreeAtomRT(rt, mi->import_name); } - js_free(ctx, m->import_entries); - js_free(ctx, m->async_parent_modules); + js_free_rt(rt, m->import_entries); + js_free_rt(rt, m->async_parent_modules); - JS_FreeValue(ctx, m->module_ns); - JS_FreeValue(ctx, m->func_obj); - JS_FreeValue(ctx, m->eval_exception); - JS_FreeValue(ctx, m->meta_obj); - JS_FreeValue(ctx, m->promise); - JS_FreeValue(ctx, m->resolving_funcs[0]); - JS_FreeValue(ctx, m->resolving_funcs[1]); - JS_FreeValue(ctx, m->private_value); - list_del(&m->link); - js_free(ctx, m); + JS_FreeValueRT(rt, m->module_ns); + JS_FreeValueRT(rt, m->func_obj); + JS_FreeValueRT(rt, m->eval_exception); + JS_FreeValueRT(rt, m->meta_obj); + JS_FreeValueRT(rt, m->promise); + JS_FreeValueRT(rt, m->resolving_funcs[0]); + JS_FreeValueRT(rt, m->resolving_funcs[1]); + JS_FreeValueRT(rt, m->private_value); + /* during the GC the finalizers are called in an arbitrary + order so the module may no longer be referenced by the JSContext list */ + if (m->link.next) { + list_del(&m->link); + } + remove_gc_object(&m->header); + if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && m->header.ref_count != 0) { + list_add_tail(&m->header.link, &rt->gc_zero_ref_count_list); + } else { + js_free_rt(rt, m); + } } static int add_req_module_entry(JSContext *ctx, JSModuleDef *m, @@ -29833,6 +29982,14 @@ static int exec_module_list_cmp(const void *p1, const void *p2, void *opaque) static int js_execute_async_module(JSContext *ctx, JSModuleDef *m); static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m, JSValue *pvalue); +#ifdef DUMP_MODULE_EXEC +static void js_dump_module(JSContext *ctx, const char *str, JSModuleDef *m) +{ + char buf1[ATOM_GET_STR_BUF_SIZE]; + static const char *module_status_str[] = { "unlinked", "linking", "linked", "evaluating", "evaluating_async", "evaluated" }; + printf("%s: %s status=%s\n", str, JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name), module_status_str[m->status]); +} +#endif static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data) @@ -29841,6 +29998,9 @@ static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst t JSValueConst error = argv[0]; int i; +#ifdef DUMP_MODULE_EXEC + js_dump_module(ctx, __func__, module); +#endif if (js_check_stack_overflow(ctx->rt, 0)) return JS_ThrowStackOverflow(ctx); @@ -29856,6 +30016,7 @@ static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst t module->eval_has_exception = TRUE; module->eval_exception = JS_DupValue(ctx, error); module->status = JS_MODULE_STATUS_EVALUATED; + module->async_evaluation = FALSE; for(i = 0; i < module->async_parent_modules_count; i++) { JSModuleDef *m = module->async_parent_modules[i]; @@ -29882,6 +30043,9 @@ static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst ExecModuleList exec_list_s, *exec_list = &exec_list_s; int i; +#ifdef DUMP_MODULE_EXEC + js_dump_module(ctx, __func__, module); +#endif if (module->status == JS_MODULE_STATUS_EVALUATED) { assert(module->eval_has_exception); return JS_UNDEFINED; @@ -29907,6 +30071,9 @@ static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst for(i = 0; i < exec_list->count; i++) { JSModuleDef *m = exec_list->tab[i]; +#ifdef DUMP_MODULE_EXEC + printf(" %d/%d", i, exec_list->count); js_dump_module(ctx, "", m); +#endif if (m->status == JS_MODULE_STATUS_EVALUATED) { assert(m->eval_has_exception); } else if (m->has_tla) { @@ -29921,6 +30088,7 @@ static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst JS_FreeValue(ctx, m_obj); JS_FreeValue(ctx, error); } else { + m->async_evaluation = FALSE; js_set_module_evaluated(ctx, m); } } @@ -29933,6 +30101,9 @@ static int js_execute_async_module(JSContext *ctx, JSModuleDef *m) { JSValue promise, m_obj; JSValue resolve_funcs[2], ret_val; +#ifdef DUMP_MODULE_EXEC + js_dump_module(ctx, __func__, m); +#endif promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0); if (JS_IsException(promise)) return -1; @@ -29952,6 +30123,9 @@ static int js_execute_async_module(JSContext *ctx, JSModuleDef *m) static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m, JSValue *pvalue) { +#ifdef DUMP_MODULE_EXEC + js_dump_module(ctx, __func__, m); +#endif if (m->init_func) { /* C module init : no asynchronous execution */ if (m->init_func(ctx, m) < 0) @@ -29991,19 +30165,16 @@ static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m, JSModuleDef *m1; int i; +#ifdef DUMP_MODULE_EXEC + js_dump_module(ctx, __func__, m); +#endif + if (js_check_stack_overflow(ctx->rt, 0)) { JS_ThrowStackOverflow(ctx); *pvalue = JS_GetException(ctx); return -1; } -#ifdef DUMP_MODULE_RESOLVE - { - char buf1[ATOM_GET_STR_BUF_SIZE]; - printf("js_inner_module_evaluation '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); - } -#endif - if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || m->status == JS_MODULE_STATUS_EVALUATED) { if (m->eval_has_exception) { @@ -30104,6 +30275,9 @@ static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m) JSModuleDef *m1, *stack_top; JSValue ret_val, result; +#ifdef DUMP_MODULE_EXEC + js_dump_module(ctx, __func__, m); +#endif assert(m->status == JS_MODULE_STATUS_LINKED || m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || m->status == JS_MODULE_STATUS_EVALUATED); @@ -30136,6 +30310,9 @@ static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m) 1, (JSValueConst *)&m->eval_exception); JS_FreeValue(ctx, ret_val); } else { +#ifdef DUMP_MODULE_EXEC + js_dump_module(ctx, " done", m); +#endif assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || m->status == JS_MODULE_STATUS_EVALUATED); assert(!m->eval_has_exception); @@ -30663,7 +30840,7 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx, fd->is_eval = is_eval; fd->is_func_expr = is_func_expr; - js_dbuf_init(ctx, &fd->byte_code); + js_dbuf_bytecode_init(ctx, &fd->byte_code); fd->last_opcode_pos = -1; fd->func_name = JS_ATOM_NULL; fd->var_object_idx = -1; @@ -32758,7 +32935,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) cc.bc_buf = bc_buf = s->byte_code.buf; cc.bc_len = bc_len = s->byte_code.size; - js_dbuf_init(ctx, &bc_out); + js_dbuf_bytecode_init(ctx, &bc_out); /* first pass for runtime checks (must be done before the variables are created) */ @@ -33378,7 +33555,7 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) cc.bc_buf = bc_buf = s->byte_code.buf; cc.bc_len = bc_len = s->byte_code.size; - js_dbuf_init(ctx, &bc_out); + js_dbuf_bytecode_init(ctx, &bc_out); #if SHORT_OPCODES if (s->jump_size) { @@ -35788,7 +35965,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, fail1: /* XXX: should free all the unresolved dependencies */ if (m) - js_free_module_def(ctx, m); + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); return JS_EXCEPTION; } @@ -37500,7 +37677,7 @@ static JSValue JS_ReadModule(BCReaderState *s) return obj; fail: if (m) { - js_free_module_def(ctx, m); + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); } return JS_EXCEPTION; } @@ -53558,22 +53735,12 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, if (special == special_lastIndexOf) { k = len - 1; if (argc > 1) { - if (JS_ToFloat64(ctx, &d, argv[1])) + int64_t k1; + if (JS_ToInt64Clamp(ctx, &k1, argv[1], -1, len - 1, len)) goto exception; - if (isnan(d)) { - k = 0; - } else { - if (d >= 0) { - if (d < k) { - k = d; - } - } else { - d += len; - if (d < 0) - goto done; - k = d; - } - } + k = k1; + if (k < 0) + goto done; } stop = -1; inc = -1; @@ -54054,16 +54221,17 @@ static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val, if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) goto exception; + shift = typed_array_size_log2(p->class_id); + ta = p->u.typed_array; + /* Read byteOffset (ta->offset) even if detached */ + offset = ta->offset + (start << shift); + final = len; if (!JS_IsUndefined(argv[1])) { if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len)) goto exception; } count = max_int(final - start, 0); - shift = typed_array_size_log2(p->class_id); - ta = p->u.typed_array; - /* Read byteOffset (ta->offset) even if detached */ - offset = ta->offset + (start << shift); ta_buffer = js_typed_array_get_buffer(ctx, this_val, 0); if (JS_IsException(ta_buffer)) goto exception; @@ -55647,7 +55815,7 @@ typedef struct JSFinRecEntry { typedef struct JSFinalizationRegistryData { JSWeakRefHeader weakref_header; struct list_head entries; /* list of JSFinRecEntry.link */ - JSContext *ctx; + JSContext *realm; JSValue cb; } JSFinalizationRegistryData; @@ -55664,6 +55832,7 @@ static void js_finrec_finalizer(JSRuntime *rt, JSValue val) js_free_rt(rt, fre); } JS_FreeValueRT(rt, frd->cb); + JS_FreeContext(frd->realm); list_del(&frd->weakref_header.link); js_free_rt(rt, frd); } @@ -55680,6 +55849,7 @@ static void js_finrec_mark(JSRuntime *rt, JSValueConst val, JS_MarkValue(rt, fre->held_val, mark_func); } JS_MarkValue(rt, frd->cb, mark_func); + mark_func(rt, &frd->realm->header); } } @@ -55705,7 +55875,7 @@ static void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh) JSValueConst args[2]; args[0] = frd->cb; args[1] = fre->held_val; - JS_EnqueueJob(frd->ctx, js_finrec_job, 2, args); + JS_EnqueueJob(frd->realm, js_finrec_job, 2, args); js_weakref_free(rt, fre->target); js_weakref_free(rt, fre->token); @@ -55740,7 +55910,7 @@ static JSValue js_finrec_constructor(JSContext *ctx, JSValueConst new_target, frd->weakref_header.weakref_type = JS_WEAKREF_TYPE_FINREC; list_add_tail(&frd->weakref_header.link, &ctx->rt->weakref_list); init_list_head(&frd->entries); - frd->ctx = ctx; /* XXX: JS_DupContext() ? */ + frd->realm = JS_DupContext(ctx); frd->cb = JS_DupValue(ctx, cb); JS_SetOpaque(obj, frd); return obj; diff --git a/src/couch_quickjs/quickjs/run-test262.c b/src/couch_quickjs/quickjs/run-test262.c index 03b37c6e1..ef16025ae 100644 --- a/src/couch_quickjs/quickjs/run-test262.c +++ b/src/couch_quickjs/quickjs/run-test262.c @@ -496,8 +496,7 @@ static void *agent_start(void *arg) JS_FreeValue(ctx, ret_val); for(;;) { - JSContext *ctx1; - ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL); if (ret < 0) { js_std_dump_error(ctx); break; @@ -1270,8 +1269,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len, JS_FreeValue(ctx, res_val); } for(;;) { - JSContext *ctx1; - ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL); if (ret < 0) { res_val = JS_EXCEPTION; break; @@ -1938,10 +1936,9 @@ int run_test262_harness_test(const char *filename, BOOL is_module) JS_FreeValue(ctx, res_val); } for(;;) { - JSContext *ctx1; - ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL); if (ret < 0) { - js_std_dump_error(ctx1); + js_std_dump_error(ctx); ret_code = 1; } else if (ret == 0) { break; diff --git a/src/couch_quickjs/quickjs/test262.conf b/src/couch_quickjs/quickjs/test262.conf index 327759454..c099f2fe6 100644 --- a/src/couch_quickjs/quickjs/test262.conf +++ b/src/couch_quickjs/quickjs/test262.conf @@ -337,6 +337,8 @@ test262/test/staging/sm/RegExp/source.js test262/test/staging/sm/RegExp/escape.js # source directives are not standard yet test262/test/staging/sm/syntax/syntax-parsed-arrow-then-directive.js +# returning "bound fn" as initialName for a function is permitted by the spec +test262/test/staging/sm/Function/function-toString-builtin.js [tests] # list test files or use config.testdir diff --git a/src/couch_quickjs/quickjs/test262_errors.txt b/src/couch_quickjs/quickjs/test262_errors.txt index a252d6ec3..c565fa242 100644 --- a/src/couch_quickjs/quickjs/test262_errors.txt +++ b/src/couch_quickjs/quickjs/test262_errors.txt @@ -1,6 +1,12 @@ +test262/test/annexB/language/expressions/assignmenttargettype/callexpression-as-for-in-lhs.js:27: SyntaxError: invalid for in/of left hand-side +test262/test/annexB/language/expressions/assignmenttargettype/callexpression-as-for-of-lhs.js:27: SyntaxError: invalid for in/of left hand-side +test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-compound-assignment.js:33: SyntaxError: invalid assignment left-hand side +test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-postfix-update.js:27: SyntaxError: invalid increment/decrement operand +test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-prefix-update.js:27: SyntaxError: invalid increment/decrement operand +test262/test/annexB/language/expressions/assignmenttargettype/callexpression.js:33: SyntaxError: invalid assignment left-hand side +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 test262/test/built-ins/Atomics/notify/retrieve-length-before-index-coercion-non-shared-detached.js:34: strict mode: TypeError: ArrayBuffer is detached -test262/test/language/module-code/top-level-await/module-graphs-does-not-hang.js:10: TypeError: $DONE() not called test262/test/language/statements/expression/S12.4_A1.js:15: unexpected error type: Test262: This statement should not be evaluated. test262/test/language/statements/expression/S12.4_A1.js:15: strict mode: unexpected error type: Test262: This statement should not be evaluated. test262/test/staging/sm/Date/UTC-convert-all-arguments.js:75: Test262Error: index 1: expected 42, got Error: didn't throw Expected SameValue(«Error: didn't throw», «42») to be true @@ -11,15 +17,15 @@ test262/test/staging/sm/Function/arguments-parameter-shadowing.js:15: Test262Err test262/test/staging/sm/Function/constructor-binding.js:12: Test262Error: Expected SameValue(«"function"», «"undefined"») to be true test262/test/staging/sm/Function/function-bind.js:14: Test262Error: Conforms to NativeFunction Syntax: "function bound unbound() {\n [native code]\n}" test262/test/staging/sm/Function/function-name-for.js:12: Test262Error: Expected SameValue(«""», «"forInHead"») to be true -test262/test/staging/sm/Function/function-toString-builtin.js:14: Test262Error: Expected match to '/^\s*function\s*(get|set)?\s*(\w+|(?:'[^']*')|(?:"[^"]*")|\d+|(?:\[[^\]]+\]))?\s*\(\s*\)\s*\{\s*\[native code\]\s*\}\s*$/', Actual value 'function bound fn() { - [native code] -}' Expected SameValue(«null», «null») to be false test262/test/staging/sm/Function/implicit-this-in-parameter-expression.js:13: Test262Error: Expected SameValue(«[object Object]», «undefined») to be true test262/test/staging/sm/Function/invalid-parameter-list.js:35: Error: Assertion failed: expected exception SyntaxError, no exception thrown test262/test/staging/sm/RegExp/constructor-ordering-2.js:15: Test262Error: Expected SameValue(«false», «true») to be true -test262/test/staging/sm/RegExp/regress-613820-1.js:13: Test262Error: Expected SameValue(«"aaa"», «"aa"») to be true -test262/test/staging/sm/RegExp/regress-613820-2.js:13: Test262Error: Expected SameValue(«"f"», «undefined») to be true -test262/test/staging/sm/RegExp/regress-613820-3.js:13: Test262Error: Expected SameValue(«"aab"», «"aa"») to be true +test262/test/staging/sm/RegExp/regress-613820-1.js:12: Test262Error: Actual [aaa, aa, a] and expected [aa, a, a] should have the same contents. +test262/test/staging/sm/RegExp/regress-613820-1.js:12: strict mode: Test262Error: Actual [aaa, aa, a] and expected [aa, a, a] should have the same contents. +test262/test/staging/sm/RegExp/regress-613820-2.js:12: Test262Error: Actual [foobar, f, o, o, b, a, r] and expected [foobar, undefined, undefined, undefined, b, a, r] should have the same contents. +test262/test/staging/sm/RegExp/regress-613820-2.js:12: strict mode: Test262Error: Actual [foobar, f, o, o, b, a, r] and expected [foobar, undefined, undefined, undefined, b, a, r] should have the same contents. +test262/test/staging/sm/RegExp/regress-613820-3.js:12: Test262Error: Actual [aab, a, undefined, ab] and expected [aa, undefined, a, undefined] should have the same contents. +test262/test/staging/sm/RegExp/regress-613820-3.js:12: strict mode: Test262Error: Actual [aab, a, undefined, ab] and expected [aa, undefined, a, undefined] should have the same contents. test262/test/staging/sm/TypedArray/constructor-buffer-sequence.js:73: Error: Assertion failed: expected exception ExpectedError, got Error: Poisoned Value test262/test/staging/sm/TypedArray/prototype-constructor-identity.js:17: Test262Error: Expected SameValue(«2», «6») to be true test262/test/staging/sm/TypedArray/set-detached-bigint.js:27: Error: Assertion failed: expected exception SyntaxError, got RangeError: invalid array length diff --git a/src/couch_quickjs/quickjs/tests/test262.patch b/src/couch_quickjs/quickjs/tests/test262.patch index c8885e658..e488df829 100644 --- a/src/couch_quickjs/quickjs/tests/test262.patch +++ b/src/couch_quickjs/quickjs/tests/test262.patch @@ -71,10 +71,10 @@ index b397be0..c197ddc 100644 return result; } diff --git a/harness/sm/non262.js b/harness/sm/non262.js -index c1829e3..3a3ee27 100644 +index 89df923..79ded15 100644 --- a/harness/sm/non262.js +++ b/harness/sm/non262.js -@@ -41,8 +41,6 @@ globalThis.createNewGlobal = function() { +@@ -34,8 +34,6 @@ globalThis.createNewGlobal = function() { return $262.createRealm().global } @@ -83,15 +83,8 @@ index c1829e3..3a3ee27 100644 function assertEq(...args) { assert.sameValue(...args) } -@@ -71,4 +69,4 @@ if (globalThis.createExternalArrayBuffer === undefined) { - if (globalThis.enableGeckoProfilingWithSlowAssertions === undefined) { - globalThis.enableGeckoProfilingWithSlowAssertions = globalThis.enableGeckoProfiling = - globalThis.disableGeckoProfiling = () => {} --} -\ No newline at end of file -+} diff --git a/test/staging/sm/extensions/regress-469625-01.js b/test/staging/sm/extensions/regress-469625-01.js -index 5b62aeb..da07aae 100644 +index 81f84fc..4652002 100644 --- a/test/staging/sm/extensions/regress-469625-01.js +++ b/test/staging/sm/extensions/regress-469625-01.js @@ -14,8 +14,7 @@ esid: pending @@ -104,17 +97,17 @@ index 5b62aeb..da07aae 100644 //----------------------------------------------------------------------------- -@@ -27,9 +26,6 @@ function test() - printBugNumber(BUGNUMBER); - printStatus (summary); - +@@ -24,9 +23,6 @@ test(); + + function test() + { - expect = 'TypeError: [].__proto__ is not a function'; - - Array.prototype.__proto__ = function () { return 3; }; try -@@ -38,8 +34,10 @@ function test() +@@ -35,8 +31,10 @@ function test() } catch(ex) {
