You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by va...@apache.org on 2025/08/25 19:44:37 UTC

(couchdb) branch next-quickjs-update created (now d5dc23a4e)

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

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


      at d5dc23a4e QuickJS Update

This branch includes the following new commits:

     new d5dc23a4e QuickJS Update

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(couchdb) 01/01: QuickJS Update

Posted by va...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit d5dc23a4e700c98bd3d651fcb2403ea3484c6164
Author: Nick Vatamaniuc <va...@gmail.com>
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)
    {