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