summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml1
-rw-r--r--Changelog15
-rw-r--r--TODO4
-rw-r--r--doc/quickjs.texi11
-rw-r--r--examples/hello_module.js4
-rw-r--r--examples/message.json2
-rw-r--r--libunicode-table.h1
-rw-r--r--libunicode.c20
-rw-r--r--qjs.c2
-rw-r--r--qjsc.c104
-rw-r--r--quickjs-libc.c170
-rw-r--r--quickjs-libc.h8
-rw-r--r--quickjs-opcode.h2
-rw-r--r--quickjs.c972
-rw-r--r--quickjs.h34
-rw-r--r--run-test262.c63
-rw-r--r--test262.conf20
-rw-r--r--test262_errors.txt31
-rw-r--r--tests/assert.js10
-rw-r--r--tests/test262.patch48
-rw-r--r--tests/test_builtin.js2
-rw-r--r--tests/test_language.js2
-rw-r--r--tests/test_std.js18
-rw-r--r--unicode_gen.c5
24 files changed, 1178 insertions, 371 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index bec4a48..c9ccf62 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -214,6 +214,7 @@ jobs:
submodules: true
- name: Install MinGW and Wine
run: |
+ sudo apt update
sudo apt install -y wine mingw-w64
cp /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll .
- name: Setup Wine
diff --git a/Changelog b/Changelog
index 7cc3399..b1443f5 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,18 @@
+- added JSON modules and import attributes
+- added JS_PrintValue() API
+- qjs: pretty print objects in print() and console.log()
+- qjs: better promise rejection tracker heuristics
+- added RegExp v flag
+- added RegExp modifiers
+- added RegExp.escape
+- added Float16Array
+- added Promise.try
+- improved JSON parser spec conformance
+- qjs: improved compatibility of std.parseExtJSON() with JSON5 and
+ accept JSON5 modules
+- added JS_FreePropertyEnum() and JS_AtomToCStringLen() API
+- added Error.isError()
+
2025-04-26:
- removed the bignum extensions and qjscalc
diff --git a/TODO b/TODO
index 4e07eaa..651a9f1 100644
--- a/TODO
+++ b/TODO
@@ -62,5 +62,5 @@ Optimization ideas:
Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
-Result: 60/79202 errors, 1610 excluded, 6738 skipped
-Test262 commit: 27622d764767dcb3778784884022c2c7de5769b8
+Result: 47/79398 errors, 1637 excluded, 6771 skipped
+Test262 commit: 1e38cbeb1c878a352b55c3ebe03ee8eda74a33ed
diff --git a/doc/quickjs.texi b/doc/quickjs.texi
index eef00b7..9130b47 100644
--- a/doc/quickjs.texi
+++ b/doc/quickjs.texi
@@ -449,17 +449,20 @@ optional properties:
@item parseExtJSON(str)
- Parse @code{str} using a superset of @code{JSON.parse}. The
- following extensions are accepted:
+ Parse @code{str} using a superset of @code{JSON.parse}. The superset
+ is very close to the JSON5 specification. The following extensions
+ are accepted:
@itemize
@item Single line and multiline comments
@item unquoted properties (ASCII-only Javascript identifiers)
@item trailing comma in array and object definitions
@item single quoted strings
+ @item @code{\v} escape and multi-line strings with trailing @code{\}
@item @code{\f} and @code{\v} are accepted as space characters
- @item leading plus in numbers
- @item octal (@code{0o} prefix) and hexadecimal (@code{0x} prefix) numbers
+ @item leading plus or decimal point in numbers
+ @item hexadecimal (@code{0x} prefix), octal (@code{0o} prefix) and binary (@code{0b} prefix) integers
+ @item @code{NaN} and @code{Infinity} are accepted as numbers
@end itemize
@end table
diff --git a/examples/hello_module.js b/examples/hello_module.js
index 463660f..5d4c78e 100644
--- a/examples/hello_module.js
+++ b/examples/hello_module.js
@@ -1,6 +1,8 @@
-/* example of JS module */
+/* example of JS and JSON modules */
import { fib } from "./fib_module.js";
+import msg from "./message.json";
console.log("Hello World");
console.log("fib(10)=", fib(10));
+console.log("msg=", msg);
diff --git a/examples/message.json b/examples/message.json
new file mode 100644
index 0000000..3b7fe48
--- /dev/null
+++ b/examples/message.json
@@ -0,0 +1,2 @@
+{ "x" : 1, "tab": [ 1, 2, 3 ] }
+
diff --git a/libunicode-table.h b/libunicode-table.h
index 0120ea9..67df6b3 100644
--- a/libunicode-table.h
+++ b/libunicode-table.h
@@ -3130,6 +3130,7 @@ typedef enum {
} UnicodeScriptEnum;
static const char unicode_script_name_table[] =
+ "Unknown,Zzzz" "\0"
"Adlam,Adlm" "\0"
"Ahom,Ahom" "\0"
"Anatolian_Hieroglyphs,Hluw" "\0"
diff --git a/libunicode.c b/libunicode.c
index b4a0206..3791523 100644
--- a/libunicode.c
+++ b/libunicode.c
@@ -1285,8 +1285,6 @@ int unicode_script(CharRange *cr,
script_idx = unicode_find_name(unicode_script_name_table, script_name);
if (script_idx < 0)
return -2;
- /* Note: we remove the "Unknown" Script */
- script_idx += UNICODE_SCRIPT_Unknown + 1;
is_common = (script_idx == UNICODE_SCRIPT_Common ||
script_idx == UNICODE_SCRIPT_Inherited);
@@ -1316,17 +1314,21 @@ int unicode_script(CharRange *cr,
n |= *p++;
n += 96 + (1 << 12);
}
- if (type == 0)
- v = 0;
- else
- v = *p++;
c1 = c + n + 1;
- if (v == script_idx) {
- if (cr_add_interval(cr1, c, c1))
- goto fail;
+ if (type != 0) {
+ v = *p++;
+ if (v == script_idx || script_idx == UNICODE_SCRIPT_Unknown) {
+ if (cr_add_interval(cr1, c, c1))
+ goto fail;
+ }
}
c = c1;
}
+ if (script_idx == UNICODE_SCRIPT_Unknown) {
+ /* Unknown is all the characters outside scripts */
+ if (cr_invert(cr1))
+ goto fail;
+ }
if (is_ext) {
/* add the script extensions */
diff --git a/qjs.c b/qjs.c
index 2eaa9ee..a88e39a 100644
--- a/qjs.c
+++ b/qjs.c
@@ -465,7 +465,7 @@ int main(int argc, char **argv)
}
/* loader for ES6 modules */
- JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
+ JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);
if (dump_unhandled_promise_rejection) {
JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker,
diff --git a/qjsc.c b/qjsc.c
index f9e1928..49aa449 100644
--- a/qjsc.c
+++ b/qjsc.c
@@ -170,14 +170,24 @@ static void dump_hex(FILE *f, const uint8_t *buf, size_t len)
fprintf(f, "\n");
}
+typedef enum {
+ CNAME_TYPE_SCRIPT,
+ CNAME_TYPE_MODULE,
+ CNAME_TYPE_JSON_MODULE,
+} CNameTypeEnum;
+
static void output_object_code(JSContext *ctx,
FILE *fo, JSValueConst obj, const char *c_name,
- BOOL load_only)
+ CNameTypeEnum c_name_type)
{
uint8_t *out_buf;
size_t out_buf_len;
int flags;
- flags = JS_WRITE_OBJ_BYTECODE;
+
+ if (c_name_type == CNAME_TYPE_JSON_MODULE)
+ flags = 0;
+ else
+ flags = JS_WRITE_OBJ_BYTECODE;
if (byte_swap)
flags |= JS_WRITE_OBJ_BSWAP;
out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags);
@@ -186,7 +196,7 @@ static void output_object_code(JSContext *ctx,
exit(1);
}
- namelist_add(&cname_list, c_name, NULL, load_only);
+ namelist_add(&cname_list, c_name, NULL, c_name_type);
fprintf(fo, "const uint32_t %s_size = %u;\n\n",
c_name, (unsigned int)out_buf_len);
@@ -227,7 +237,8 @@ static void find_unique_cname(char *cname, size_t cname_size)
}
JSModuleDef *jsc_module_loader(JSContext *ctx,
- const char *module_name, void *opaque)
+ const char *module_name, void *opaque,
+ JSValueConst attributes)
{
JSModuleDef *m;
namelist_entry_t *e;
@@ -249,9 +260,9 @@ JSModuleDef *jsc_module_loader(JSContext *ctx,
} else {
size_t buf_len;
uint8_t *buf;
- JSValue func_val;
char cname[1024];
-
+ int res;
+
buf = js_load_file(ctx, &buf_len, module_name);
if (!buf) {
JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
@@ -259,21 +270,59 @@ JSModuleDef *jsc_module_loader(JSContext *ctx,
return NULL;
}
- /* compile the module */
- func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
- JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
- js_free(ctx, buf);
- if (JS_IsException(func_val))
- return NULL;
- get_c_name(cname, sizeof(cname), module_name);
- if (namelist_find(&cname_list, cname)) {
- find_unique_cname(cname, sizeof(cname));
- }
- output_object_code(ctx, outfile, func_val, cname, TRUE);
+ res = js_module_test_json(ctx, attributes);
+ if (has_suffix(module_name, ".json") || res > 0) {
+ /* compile as JSON or JSON5 depending on "type" */
+ JSValue val;
+ int flags;
+
+ if (res == 2)
+ flags = JS_PARSE_JSON_EXT;
+ else
+ flags = 0;
+ val = JS_ParseJSON2(ctx, (char *)buf, buf_len, module_name, flags);
+ js_free(ctx, buf);
+ if (JS_IsException(val))
+ return NULL;
+ /* create a dummy module */
+ m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
+ if (!m) {
+ JS_FreeValue(ctx, val);
+ return NULL;
+ }
+
+ get_c_name(cname, sizeof(cname), module_name);
+ if (namelist_find(&cname_list, cname)) {
+ find_unique_cname(cname, sizeof(cname));
+ }
+
+ /* output the module name */
+ fprintf(outfile, "static const uint8_t %s_module_name[] = {\n",
+ cname);
+ dump_hex(outfile, (const uint8_t *)module_name, strlen(module_name) + 1);
+ fprintf(outfile, "};\n\n");
- /* the module is already referenced, so we must free it */
- m = JS_VALUE_GET_PTR(func_val);
- JS_FreeValue(ctx, func_val);
+ output_object_code(ctx, outfile, val, cname, CNAME_TYPE_JSON_MODULE);
+ JS_FreeValue(ctx, val);
+ } else {
+ JSValue func_val;
+
+ /* compile the module */
+ func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
+ JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
+ js_free(ctx, buf);
+ if (JS_IsException(func_val))
+ return NULL;
+ get_c_name(cname, sizeof(cname), module_name);
+ if (namelist_find(&cname_list, cname)) {
+ find_unique_cname(cname, sizeof(cname));
+ }
+ output_object_code(ctx, outfile, func_val, cname, CNAME_TYPE_MODULE);
+
+ /* the module is already referenced, so we must free it */
+ m = JS_VALUE_GET_PTR(func_val);
+ JS_FreeValue(ctx, func_val);
+ }
}
return m;
}
@@ -314,7 +363,7 @@ static void compile_file(JSContext *ctx, FILE *fo,
} else {
get_c_name(c_name, sizeof(c_name), filename);
}
- output_object_code(ctx, fo, obj, c_name, FALSE);
+ output_object_code(ctx, fo, obj, c_name, CNAME_TYPE_SCRIPT);
JS_FreeValue(ctx, obj);
}
@@ -709,7 +758,7 @@ int main(int argc, char **argv)
JS_SetStripInfo(rt, strip_flags);
/* loader for ES6 modules */
- JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL);
+ JS_SetModuleLoaderFunc2(rt, NULL, jsc_module_loader, NULL, NULL);
fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n"
"\n"
@@ -732,7 +781,7 @@ int main(int argc, char **argv)
}
for(i = 0; i < dynamic_module_list.count; i++) {
- if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) {
+ if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL, JS_UNDEFINED)) {
fprintf(stderr, "Could not load dynamic module '%s'\n",
dynamic_module_list.array[i].name);
exit(1);
@@ -770,9 +819,12 @@ int main(int argc, char **argv)
}
for(i = 0; i < cname_list.count; i++) {
namelist_entry_t *e = &cname_list.array[i];
- if (e->flags) {
+ if (e->flags == CNAME_TYPE_MODULE) {
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n",
e->name, e->name);
+ } else if (e->flags == CNAME_TYPE_JSON_MODULE) {
+ fprintf(fo, " js_std_eval_binary_json_module(ctx, %s, %s_size, (const char *)%s_module_name);\n",
+ e->name, e->name, e->name);
}
}
fprintf(fo,
@@ -788,7 +840,7 @@ int main(int argc, char **argv)
/* add the module loader if necessary */
if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
- fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
+ fprintf(fo, " JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);\n");
}
fprintf(fo,
@@ -797,7 +849,7 @@ int main(int argc, char **argv)
for(i = 0; i < cname_list.count; i++) {
namelist_entry_t *e = &cname_list.array[i];
- if (!e->flags) {
+ if (e->flags == CNAME_TYPE_SCRIPT) {
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n",
e->name, e->name);
}
diff --git a/quickjs-libc.c b/quickjs-libc.c
index 7393c00..023d895 100644
--- a/quickjs-libc.c
+++ b/quickjs-libc.c
@@ -591,17 +591,101 @@ int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
return 0;
}
-JSModuleDef *js_module_loader(JSContext *ctx,
- const char *module_name, void *opaque)
+static int json_module_init(JSContext *ctx, JSModuleDef *m)
+{
+ JSValue val;
+ val = JS_GetModulePrivateValue(ctx, m);
+ JS_SetModuleExport(ctx, m, "default", val);
+ return 0;
+}
+
+static JSModuleDef *create_json_module(JSContext *ctx, const char *module_name, JSValue val)
{
JSModuleDef *m;
+ m = JS_NewCModule(ctx, module_name, json_module_init);
+ if (!m) {
+ JS_FreeValue(ctx, val);
+ return NULL;
+ }
+ /* only export the "default" symbol which will contain the JSON object */
+ JS_AddModuleExport(ctx, m, "default");
+ JS_SetModulePrivateValue(ctx, m, val);
+ return m;
+}
+
+/* in order to conform with the specification, only the keys should be
+ tested and not the associated values. */
+int js_module_check_attributes(JSContext *ctx, void *opaque,
+ JSValueConst attributes)
+{
+ JSPropertyEnum *tab;
+ uint32_t i, len;
+ int ret;
+ const char *cstr;
+ size_t cstr_len;
+
+ if (JS_GetOwnPropertyNames(ctx, &tab, &len, attributes, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK))
+ return -1;
+ ret = 0;
+ for(i = 0; i < len; i++) {
+ cstr = JS_AtomToCStringLen(ctx, &cstr_len, tab[i].atom);
+ if (!cstr) {
+ ret = -1;
+ break;
+ }
+ if (!(cstr_len == 4 && !memcmp(cstr, "type", cstr_len))) {
+ JS_ThrowTypeError(ctx, "import attribute '%s' is not supported", cstr);
+ ret = -1;
+ }
+ JS_FreeCString(ctx, cstr);
+ if (ret)
+ break;
+ }
+ JS_FreePropertyEnum(ctx, tab, len);
+ return ret;
+}
+/* return > 0 if the attributes indicate a JSON module */
+int js_module_test_json(JSContext *ctx, JSValueConst attributes)
+{
+ JSValue str;
+ const char *cstr;
+ size_t len;
+ BOOL res;
+
+ if (JS_IsUndefined(attributes))
+ return FALSE;
+ str = JS_GetPropertyStr(ctx, attributes, "type");
+ if (!JS_IsString(str))
+ return FALSE;
+ cstr = JS_ToCStringLen(ctx, &len, str);
+ JS_FreeValue(ctx, str);
+ if (!cstr)
+ return FALSE;
+ /* XXX: raise an error if unknown type ? */
+ if (len == 4 && !memcmp(cstr, "json", len)) {
+ res = 1;
+ } else if (len == 5 && !memcmp(cstr, "json5", len)) {
+ res = 2;
+ } else {
+ res = 0;
+ }
+ JS_FreeCString(ctx, cstr);
+ return res;
+}
+
+JSModuleDef *js_module_loader(JSContext *ctx,
+ const char *module_name, void *opaque,
+ JSValueConst attributes)
+{
+ JSModuleDef *m;
+ int res;
+
if (has_suffix(module_name, ".so")) {
m = js_module_loader_so(ctx, module_name);
} else {
size_t buf_len;
uint8_t *buf;
- JSValue func_val;
buf = js_load_file(ctx, &buf_len, module_name);
if (!buf) {
@@ -609,18 +693,36 @@ JSModuleDef *js_module_loader(JSContext *ctx,
module_name);
return NULL;
}
-
- /* compile the module */
- func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
- JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
- js_free(ctx, buf);
- if (JS_IsException(func_val))
- return NULL;
- /* XXX: could propagate the exception */
- js_module_set_import_meta(ctx, func_val, TRUE, FALSE);
- /* the module is already referenced, so we must free it */
- m = JS_VALUE_GET_PTR(func_val);
- JS_FreeValue(ctx, func_val);
+ res = js_module_test_json(ctx, attributes);
+ if (has_suffix(module_name, ".json") || res > 0) {
+ /* compile as JSON or JSON5 depending on "type" */
+ JSValue val;
+ int flags;
+ if (res == 2)
+ flags = JS_PARSE_JSON_EXT;
+ else
+ flags = 0;
+ val = JS_ParseJSON2(ctx, (char *)buf, buf_len, module_name, flags);
+ js_free(ctx, buf);
+ if (JS_IsException(val))
+ return NULL;
+ m = create_json_module(ctx, module_name, val);
+ if (!m)
+ return NULL;
+ } else {
+ JSValue func_val;
+ /* compile the module */
+ func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
+ JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
+ js_free(ctx, buf);
+ if (JS_IsException(func_val))
+ return NULL;
+ /* XXX: could propagate the exception */
+ js_module_set_import_meta(ctx, func_val, TRUE, FALSE);
+ /* the module is already referenced, so we must free it */
+ m = JS_VALUE_GET_PTR(func_val);
+ JS_FreeValue(ctx, func_val);
+ }
}
return m;
}
@@ -2938,9 +3040,7 @@ static char **build_envp(JSContext *ctx, JSValueConst obj)
JS_FreeCString(ctx, str);
}
done:
- for(i = 0; i < len; i++)
- JS_FreeAtom(ctx, tab[i].atom);
- js_free(ctx, tab);
+ JS_FreePropertyEnum(ctx, tab, len);
return envp;
fail:
if (envp) {
@@ -3480,7 +3580,7 @@ static void *worker_func(void *opaque)
JS_SetStripInfo(rt, args->strip_flags);
js_std_init_handlers(rt);
- JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
+ JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);
/* set the pipe to communicate with the parent */
ts = JS_GetRuntimeOpaque(rt);
@@ -4130,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;
}
}
@@ -4171,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);
@@ -4223,3 +4320,22 @@ void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
JS_FreeValue(ctx, val);
}
}
+
+void js_std_eval_binary_json_module(JSContext *ctx,
+ const uint8_t *buf, size_t buf_len,
+ const char *module_name)
+{
+ JSValue obj;
+ JSModuleDef *m;
+
+ obj = JS_ReadObject(ctx, buf, buf_len, 0);
+ if (JS_IsException(obj))
+ goto exception;
+ m = create_json_module(ctx, module_name, obj);
+ if (!m) {
+ exception:
+ js_std_dump_error(ctx);
+ exit(1);
+ }
+}
+
diff --git a/quickjs-libc.h b/quickjs-libc.h
index 850484f..5c8301b 100644
--- a/quickjs-libc.h
+++ b/quickjs-libc.h
@@ -44,10 +44,16 @@ void js_std_dump_error(JSContext *ctx);
uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
JS_BOOL use_realpath, JS_BOOL is_main);
+int js_module_test_json(JSContext *ctx, JSValueConst attributes);
+int js_module_check_attributes(JSContext *ctx, void *opaque, JSValueConst attributes);
JSModuleDef *js_module_loader(JSContext *ctx,
- const char *module_name, void *opaque);
+ const char *module_name, void *opaque,
+ JSValueConst attributes);
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
int flags);
+void js_std_eval_binary_json_module(JSContext *ctx,
+ const uint8_t *buf, size_t buf_len,
+ const char *module_name);
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
JSValueConst reason,
JS_BOOL is_handled, void *opaque);
diff --git a/quickjs-opcode.h b/quickjs-opcode.h
index e721e17..814a7cb 100644
--- a/quickjs-opcode.h
+++ b/quickjs-opcode.h
@@ -121,7 +121,7 @@ DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
bytecode string */
DEF( get_super, 1, 1, 1, none)
-DEF( import, 1, 1, 1, none) /* dynamic module import */
+DEF( import, 1, 2, 1, none) /* dynamic module import */
DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */
DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */
diff --git a/quickjs.c b/quickjs.c
index 401022e..caad931 100644
--- a/quickjs.c
+++ b/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
@@ -280,7 +281,12 @@ struct JSRuntime {
struct list_head job_list; /* list of JSJobEntry.link */
JSModuleNormalizeFunc *module_normalize_func;
- JSModuleLoaderFunc *module_loader_func;
+ BOOL module_loader_has_attr;
+ union {
+ JSModuleLoaderFunc *module_loader_func;
+ JSModuleLoaderFunc2 *module_loader_func2;
+ } u;
+ JSModuleCheckSupportedImportAttributes *module_check_attrs;
void *module_loader_opaque;
/* timestamp for internal use in module evaluation */
int64_t module_async_evaluation_next_timestamp;
@@ -335,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
@@ -756,6 +763,7 @@ typedef struct {
typedef struct JSReqModuleEntry {
JSAtom module_name;
JSModuleDef *module; /* used using resolution */
+ JSValue attributes; /* JS_UNDEFINED or an object contains the attributes as key/value */
} JSReqModuleEntry;
typedef enum JSExportTypeEnum {
@@ -798,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;
@@ -833,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 */
@@ -844,11 +853,12 @@ struct JSModuleDef {
BOOL eval_has_exception : 8;
JSValue eval_exception;
JSValue meta_obj; /* for import.meta */
+ JSValue private_value; /* private value for C modules */
};
typedef struct JSJobEntry {
struct list_head link;
- JSContext *ctx;
+ JSContext *realm;
JSJobFunc *job_func;
int argc;
JSValue argv[0];
@@ -1213,11 +1223,11 @@ 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);
-static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier);
+static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options);
static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
static JSValue js_new_promise_capability(JSContext *ctx,
JSValue *resolving_funcs,
@@ -1773,7 +1783,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++) {
@@ -1789,7 +1799,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;
@@ -1798,15 +1811,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))
@@ -1815,7 +1829,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;
}
@@ -1896,6 +1916,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);
@@ -2171,7 +2192,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));
}
}
}
@@ -2189,11 +2216,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);
@@ -3205,15 +3230,18 @@ static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
}
/* free with JS_FreeCString() */
-const char *JS_AtomToCString(JSContext *ctx, JSAtom atom)
+const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom)
{
JSValue str;
const char *cstr;
str = JS_AtomToString(ctx, atom);
- if (JS_IsException(str))
+ if (JS_IsException(str)) {
+ if (plen)
+ *plen = 0;
return NULL;
- cstr = JS_ToCString(ctx, str);
+ }
+ cstr = JS_ToCStringLen(ctx, plen, str);
JS_FreeValue(ctx, str);
return cstr;
}
@@ -5342,6 +5370,10 @@ static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
if (!name)
name = "";
name_atom = JS_NewAtom(ctx, name);
+ if (name_atom == JS_ATOM_NULL) {
+ JS_FreeValue(ctx, func_obj);
+ return JS_EXCEPTION;
+ }
js_function_set_properties(ctx, func_obj, name_atom, length);
JS_FreeAtom(ctx, name_atom);
return func_obj;
@@ -5767,6 +5799,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();
}
@@ -5831,6 +5866,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) {
@@ -5843,9 +5879,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);
@@ -5919,6 +5952,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:
@@ -6031,6 +6065,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();
}
@@ -6127,6 +6167,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");
@@ -6149,7 +6190,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 */
@@ -6872,6 +6914,9 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
const char *str1;
JSObject *p;
+ if (!JS_IsObject(error_obj))
+ return; /* protection in the out of memory case */
+
js_dbuf_init(ctx, &dbuf);
if (filename) {
dbuf_printf(&dbuf, " at %s", filename);
@@ -6879,13 +6924,17 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
dbuf_printf(&dbuf, ":%d:%d", line_num, col_num);
dbuf_putc(&dbuf, '\n');
str = JS_NewString(ctx, filename);
+ if (JS_IsException(str))
+ return;
/* Note: SpiderMonkey does that, could update once there is a standard */
- JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_columnNumber, JS_NewInt32(ctx, col_num),
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ if (JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
+ JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
+ JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_columnNumber, JS_NewInt32(ctx, col_num),
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0) {
+ return;
+ }
}
for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
if (sf->js_mode & JS_MODE_BACKTRACE_BARRIER)
@@ -6970,9 +7019,9 @@ static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
JS_NewString(ctx, buf),
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- }
- if (add_backtrace) {
- build_backtrace(ctx, obj, NULL, 0, 0, 0);
+ if (add_backtrace) {
+ build_backtrace(ctx, obj, NULL, 0, 0, 0);
+ }
}
ret = JS_Throw(ctx, obj);
return ret;
@@ -7875,7 +7924,7 @@ static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
return 1;
}
-static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
+void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
{
uint32_t i;
if (tab) {
@@ -7969,7 +8018,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
/* set the "is_enumerable" field if necessary */
res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
if (res < 0) {
- js_free_prop_enum(ctx, tab_exotic, exotic_count);
+ JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
return -1;
}
if (res) {
@@ -8000,7 +8049,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
if (atom_count < exotic_keys_count || atom_count > INT32_MAX) {
add_overflow:
JS_ThrowOutOfMemory(ctx);
- js_free_prop_enum(ctx, tab_exotic, exotic_count);
+ JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
return -1;
}
/* XXX: need generic way to test for js_malloc(ctx, a * b) overflow */
@@ -8008,7 +8057,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
/* avoid allocating 0 bytes */
tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
if (!tab_atom) {
- js_free_prop_enum(ctx, tab_exotic, exotic_count);
+ JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
return -1;
}
@@ -8053,7 +8102,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
for(i = 0; i < len; i++) {
tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
if (tab_atom[num_index].atom == JS_ATOM_NULL) {
- js_free_prop_enum(ctx, tab_atom, num_index);
+ JS_FreePropertyEnum(ctx, tab_atom, num_index);
return -1;
}
tab_atom[num_index].is_enumerable = TRUE;
@@ -8444,6 +8493,8 @@ JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
JSAtom atom;
JSValue ret;
atom = JS_NewAtom(ctx, prop);
+ if (atom == JS_ATOM_NULL)
+ return JS_EXCEPTION;
ret = JS_GetProperty(ctx, this_obj, atom);
JS_FreeAtom(ctx, atom);
return ret;
@@ -9263,6 +9314,10 @@ int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
JSAtom atom;
int ret;
atom = JS_NewAtom(ctx, prop);
+ if (atom == JS_ATOM_NULL) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW);
JS_FreeAtom(ctx, atom);
return ret;
@@ -9819,6 +9874,10 @@ int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
JSAtom atom;
int ret;
atom = JS_NewAtom(ctx, prop);
+ if (atom == JS_ATOM_NULL) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
JS_FreeAtom(ctx, atom);
return ret;
@@ -10532,6 +10591,15 @@ static inline js_limb_t js_limb_clz(js_limb_t a)
}
#endif
+/* handle a = 0 too */
+static inline js_limb_t js_limb_safe_clz(js_limb_t a)
+{
+ if (a == 0)
+ return JS_LIMB_BITS;
+ else
+ return js_limb_clz(a);
+}
+
static js_limb_t mp_add(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2,
js_limb_t n, js_limb_t carry)
{
@@ -11880,7 +11948,7 @@ static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
r = tmp;
}
log2_radix = 31 - clz32(radix); /* floor(log2(radix)) */
- n_bits = r->len * JS_LIMB_BITS - js_limb_clz(r->tab[r->len - 1]);
+ n_bits = r->len * JS_LIMB_BITS - js_limb_safe_clz(r->tab[r->len - 1]);
/* n_digits is exact only if radix is a power of
two. Otherwise it is >= the exact number of digits */
n_digits = (n_bits + log2_radix - 1) / log2_radix;
@@ -12127,7 +12195,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
case ATOD_TYPE_FLOAT64:
{
double d;
- d = js_atod(buf,NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY,
+ d = js_atod(buf, NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY,
&atod_mem);
/* return int or float64 */
val = JS_NewFloat64(ctx, d);
@@ -13705,6 +13773,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;
@@ -15553,7 +15624,7 @@ static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx,
JS_FreeValue(ctx, obj1);
goto fail;
}
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
if (tab_atom_count != 0) {
JS_FreeValue(ctx, obj1);
goto slow_path;
@@ -15637,7 +15708,7 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
return -1;
}
- js_free_prop_enum(ctx, it->tab_atom, it->atom_count);
+ JS_FreePropertyEnum(ctx, it->tab_atom, it->atom_count);
it->tab_atom = tab_atom;
it->atom_count = tab_atom_count;
it->idx = 0;
@@ -16160,10 +16231,10 @@ static __exception int JS_CopyDataProperties(JSContext *ctx,
if (ret < 0)
goto exception;
}
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
return 0;
exception:
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
return -1;
}
@@ -17380,10 +17451,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSValue val;
sf->cur_pc = pc;
- val = js_dynamic_import(ctx, sp[-1]);
+ val = js_dynamic_import(ctx, sp[-2], sp[-1]);
if (JS_IsException(val))
goto exception;
+ JS_FreeValue(ctx, sp[-2]);
JS_FreeValue(ctx, sp[-1]);
+ sp--;
sp[-1] = val;
}
BREAK;
@@ -20959,6 +21032,7 @@ static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
{
uint32_t c;
StringBuffer b_s, *b = &b_s;
+ JSValue str;
/* p points to the first byte of the template part */
if (string_buffer_init(s->ctx, b, 32))
@@ -21001,9 +21075,12 @@ static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
if (string_buffer_putc(b, c))
goto fail;
}
+ str = string_buffer_end(b);
+ if (JS_IsException(str))
+ return -1;
s->token.val = TOK_TEMPLATE;
s->token.u.str.sep = c;
- s->token.u.str.str = string_buffer_end(b);
+ s->token.u.str.str = str;
s->buf_ptr = p;
return 0;
@@ -21022,7 +21099,8 @@ static __exception int js_parse_string(JSParseState *s, int sep,
uint32_t c;
StringBuffer b_s, *b = &b_s;
const uint8_t *p_escape;
-
+ JSValue str;
+
/* string */
if (string_buffer_init(s->ctx, b, 32))
goto fail;
@@ -21031,11 +21109,6 @@ static __exception int js_parse_string(JSParseState *s, int sep,
goto invalid_char;
c = *p;
if (c < 0x20) {
- if (!s->cur_func) {
- if (do_throw)
- js_parse_error_pos(s, p, "invalid character in a JSON string");
- goto fail;
- }
if (sep == '`') {
if (c == '\r') {
if (p[1] == '\n')
@@ -21081,8 +21154,6 @@ static __exception int js_parse_string(JSParseState *s, int sep,
continue;
default:
if (c >= '0' && c <= '9') {
- if (!s->cur_func)
- goto invalid_escape; /* JSON case */
if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`')
goto parse_escape;
if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) {
@@ -21136,9 +21207,12 @@ static __exception int js_parse_string(JSParseState *s, int sep,
if (string_buffer_putc(b, c))
goto fail;
}
+ str = string_buffer_end(b);
+ if (JS_IsException(str))
+ return -1;
token->val = TOK_STRING;
token->u.str.sep = c;
- token->u.str.str = string_buffer_end(b);
+ token->u.str.str = str;
*pp = p;
return 0;
@@ -21166,6 +21240,7 @@ static __exception int js_parse_regexp(JSParseState *s)
StringBuffer b_s, *b = &b_s;
StringBuffer b2_s, *b2 = &b2_s;
uint32_t c;
+ JSValue body_str, flags_str;
p = s->buf_ptr;
p++;
@@ -21247,9 +21322,17 @@ static __exception int js_parse_regexp(JSParseState *s)
p = p_next;
}
+ body_str = string_buffer_end(b);
+ flags_str = string_buffer_end(b2);
+ if (JS_IsException(body_str) ||
+ JS_IsException(flags_str)) {
+ JS_FreeValue(s->ctx, body_str);
+ JS_FreeValue(s->ctx, flags_str);
+ return -1;
+ }
s->token.val = TOK_REGEXP;
- s->token.u.regexp.body = string_buffer_end(b);
- s->token.u.regexp.flags = string_buffer_end(b2);
+ s->token.u.regexp.body = body_str;
+ s->token.u.regexp.flags = flags_str;
s->buf_ptr = p;
return 0;
fail:
@@ -21819,6 +21902,7 @@ static __exception int next_token(JSParseState *s)
}
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
+/* XXX: accept unicode identifiers as JSON5 ? */
static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
{
const uint8_t *p;
@@ -21851,6 +21935,178 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
return atom;
}
+static int json_parse_string(JSParseState *s, const uint8_t **pp, int sep)
+{
+ const uint8_t *p, *p_next;
+ int i;
+ uint32_t c;
+ StringBuffer b_s, *b = &b_s;
+
+ if (string_buffer_init(s->ctx, b, 32))
+ goto fail;
+
+ p = *pp;
+ for(;;) {
+ if (p >= s->buf_end) {
+ goto end_of_input;
+ }
+ c = *p++;
+ if (c == sep)
+ break;
+ if (c < 0x20) {
+ js_parse_error_pos(s, p - 1, "Bad control character in string literal");
+ goto fail;
+ }
+ if (c == '\\') {
+ c = *p++;
+ switch(c) {
+ case 'b': c = '\b'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case '\\': break;
+ case '/': break;
+ case 'u':
+ c = 0;
+ for(i = 0; i < 4; i++) {
+ int h = from_hex(*p++);
+ if (h < 0) {
+ js_parse_error_pos(s, p - 1, "Bad Unicode escape");
+ goto fail;
+ }
+ c = (c << 4) | h;
+ }
+ break;
+ case '\n':
+ if (s->ext_json)
+ continue;
+ goto bad_escape;
+ case 'v':
+ if (s->ext_json) {
+ c = '\v';
+ break;
+ }
+ goto bad_escape;
+ default:
+ if (c == sep)
+ break;
+ if (p > s->buf_end)
+ goto end_of_input;
+ bad_escape:
+ js_parse_error_pos(s, p - 1, "Bad escaped character");
+ goto fail;
+ }
+ } else
+ if (c >= 0x80) {
+ c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
+ if (c > 0x10FFFF) {
+ js_parse_error_pos(s, p - 1, "Bad UTF-8 sequence");
+ goto fail;
+ }
+ p = p_next;
+ }
+ if (string_buffer_putc(b, c))
+ goto fail;
+ }
+ s->token.val = TOK_STRING;
+ s->token.u.str.sep = sep;
+ s->token.u.str.str = string_buffer_end(b);
+ *pp = p;
+ return 0;
+
+ end_of_input:
+ js_parse_error(s, "Unexpected end of JSON input");
+ fail:
+ string_buffer_free(b);
+ return -1;
+}
+
+static int json_parse_number(JSParseState *s, const uint8_t **pp)
+{
+ const uint8_t *p = *pp;
+ const uint8_t *p_start = p;
+ int radix;
+ double d;
+ JSATODTempMem atod_mem;
+
+ if (*p == '+' || *p == '-')
+ p++;
+
+ if (!is_digit(*p)) {
+ if (s->ext_json) {
+ if (strstart((const char *)p, "Infinity", (const char **)&p)) {
+ d = 1.0 / 0.0;
+ if (*p_start == '-')
+ d = -d;
+ goto done;
+ } else if (strstart((const char *)p, "NaN", (const char **)&p)) {
+ d = NAN;
+ goto done;
+ } else if (*p != '.') {
+ goto unexpected_token;
+ }
+ } else {
+ goto unexpected_token;
+ }
+ }
+
+ if (p[0] == '0') {
+ if (s->ext_json) {
+ /* also accepts base 16, 8 and 2 prefix for integers */
+ radix = 10;
+ if (p[1] == 'x' || p[1] == 'X') {
+ p += 2;
+ radix = 16;
+ } else if ((p[1] == 'o' || p[1] == 'O')) {
+ p += 2;
+ radix = 8;
+ } else if ((p[1] == 'b' || p[1] == 'B')) {
+ p += 2;
+ radix = 2;
+ }
+ if (radix != 10) {
+ /* prefix is present */
+ if (to_digit(*p) >= radix) {
+ unexpected_token:
+ return js_parse_error_pos(s, p, "Unexpected token '%c'", *p);
+ }
+ d = js_atod((const char *)p_start, (const char **)&p, 0,
+ JS_ATOD_INT_ONLY | JS_ATOD_ACCEPT_BIN_OCT, &atod_mem);
+ goto done;
+ }
+ }
+ if (is_digit(p[1]))
+ return js_parse_error_pos(s, p, "Unexpected number");
+ }
+
+ while (is_digit(*p))
+ p++;
+
+ if (*p == '.') {
+ p++;
+ if (!is_digit(*p))
+ return js_parse_error_pos(s, p, "Unterminated fractional number");
+ while (is_digit(*p))
+ p++;
+ }
+ if (*p == 'e' || *p == 'E') {
+ p++;
+ if (*p == '+' || *p == '-')
+ p++;
+ if (!is_digit(*p))
+ return js_parse_error_pos(s, p, "Exponent part is missing a number");
+ while (is_digit(*p))
+ p++;
+ }
+ d = js_atod((const char *)p_start, NULL, 10, 0, &atod_mem);
+ done:
+ s->token.val = TOK_NUMBER;
+ s->token.u.num.val = JS_NewFloat64(s->ctx, d);
+ *pp = p;
+ return 0;
+}
+
static __exception int json_next_token(JSParseState *s)
{
const uint8_t *p;
@@ -21882,7 +22138,8 @@ static __exception int json_next_token(JSParseState *s)
}
/* fall through */
case '\"':
- if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
+ p++;
+ if (json_parse_string(s, &p, c))
goto fail;
break;
case '\r': /* accept DOS and MAC newline sequences */
@@ -21972,7 +22229,6 @@ static __exception int json_next_token(JSParseState *s)
case 'Y': case 'Z':
case '_':
case '$':
- /* identifier : only pure ascii characters are accepted */
p++;
atom = json_parse_ident(s, &p, c);
if (atom == JS_ATOM_NULL)
@@ -21983,39 +22239,23 @@ static __exception int json_next_token(JSParseState *s)
s->token.val = TOK_IDENT;
break;
case '+':
- if (!s->ext_json || !is_digit(p[1]))
+ if (!s->ext_json)
goto def_token;
goto parse_number;
- case '0':
- if (is_digit(p[1]))
+ case '.':
+ if (s->ext_json && is_digit(p[1]))
+ goto parse_number;
+ else
goto def_token;
- goto parse_number;
case '-':
- if (!is_digit(p[1]))
- goto def_token;
- goto parse_number;
+ case '0':
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
case '9':
/* number */
parse_number:
- {
- JSValue ret;
- int flags, radix;
- if (!s->ext_json) {
- flags = 0;
- radix = 10;
- } else {
- flags = ATOD_ACCEPT_BIN_OCT;
- radix = 0;
- }
- ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
- flags);
- if (JS_IsException(ret))
- goto fail;
- s->token.val = TOK_NUMBER;
- s->token.u.num.val = ret;
- }
+ if (json_parse_number(s, &p))
+ goto fail;
break;
default:
if (c >= 128) {
@@ -22200,7 +22440,7 @@ BOOL JS_DetectModule(const char *input, size_t input_len)
}
static inline int get_prev_opcode(JSFunctionDef *fd) {
- if (fd->last_opcode_pos < 0)
+ if (fd->last_opcode_pos < 0 || dbuf_error(&fd->byte_code))
return OP_invalid;
else
return fd->byte_code.buf[fd->last_opcode_pos];
@@ -22265,7 +22505,11 @@ static void emit_op(JSParseState *s, uint8_t val)
static void emit_atom(JSParseState *s, JSAtom name)
{
- emit_u32(s, JS_DupAtom(s->ctx, name));
+ DynBuf *bc = &s->cur_func->byte_code;
+ if (dbuf_realloc(bc, bc->size + 4))
+ return; /* not enough memory : don't duplicate the atom */
+ put_u32(bc->buf + bc->size, JS_DupAtom(s->ctx, name));
+ bc->size += 4;
}
static int update_label(JSFunctionDef *s, int label, int delta)
@@ -22279,29 +22523,33 @@ static int update_label(JSFunctionDef *s, int label, int delta)
return ls->ref_count;
}
-static int new_label_fd(JSFunctionDef *fd, int label)
+static int new_label_fd(JSFunctionDef *fd)
{
+ int label;
LabelSlot *ls;
- if (label < 0) {
- if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
- sizeof(fd->label_slots[0]),
- &fd->label_size, fd->label_count + 1))
- return -1;
- label = fd->label_count++;
- ls = &fd->label_slots[label];
- ls->ref_count = 0;
- ls->pos = -1;
- ls->pos2 = -1;
- ls->addr = -1;
- ls->first_reloc = NULL;
- }
+ if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
+ sizeof(fd->label_slots[0]),
+ &fd->label_size, fd->label_count + 1))
+ return -1;
+ label = fd->label_count++;
+ ls = &fd->label_slots[label];
+ ls->ref_count = 0;
+ ls->pos = -1;
+ ls->pos2 = -1;
+ ls->addr = -1;
+ ls->first_reloc = NULL;
return label;
}
static int new_label(JSParseState *s)
{
- return new_label_fd(s->cur_func, -1);
+ int label;
+ label = new_label_fd(s->cur_func);
+ if (unlikely(label < 0)) {
+ dbuf_set_error(&s->cur_func->byte_code);
+ }
+ return label;
}
/* don't update the last opcode and don't emit line number info */
@@ -22329,8 +22577,11 @@ static int emit_label(JSParseState *s, int label)
static int emit_goto(JSParseState *s, int opcode, int label)
{
if (js_is_live_code(s)) {
- if (label < 0)
+ if (label < 0) {
label = new_label(s);
+ if (label < 0)
+ return -1;
+ }
emit_op(s, opcode);
emit_u32(s, label);
s->cur_func->label_slots[label].ref_count++;
@@ -24371,6 +24622,8 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
switch(opcode) {
case OP_scope_get_var:
label = new_label(s);
+ if (label < 0)
+ return -1;
emit_op(s, OP_scope_make_ref);
emit_atom(s, name);
emit_u32(s, label);
@@ -24403,6 +24656,8 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
switch(opcode) {
case OP_scope_get_var:
label = new_label(s);
+ if (label < 0)
+ return -1;
emit_op(s, OP_scope_make_ref);
emit_atom(s, name);
emit_u32(s, label);
@@ -25412,6 +25667,23 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
return js_parse_error(s, "invalid use of 'import()'");
if (js_parse_assign_expr(s))
return -1;
+ if (s->token.val == ',') {
+ if (next_token(s))
+ return -1;
+ if (s->token.val != ')') {
+ if (js_parse_assign_expr(s))
+ return -1;
+ /* accept a trailing comma */
+ if (s->token.val == ',') {
+ if (next_token(s))
+ return -1;
+ }
+ } else {
+ emit_op(s, OP_undefined);
+ }
+ } else {
+ emit_op(s, OP_undefined);
+ }
if (js_parse_expect(s, ')'))
return -1;
emit_op(s, OP_import);
@@ -25428,6 +25700,8 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
BOOL has_optional_chain = FALSE;
if (s->token.val == TOK_QUESTION_MARK_DOT) {
+ if ((parse_flags & PF_POSTFIX_CALL) == 0)
+ return js_parse_error(s, "new keyword cannot be used with an optional chain");
op_token_ptr = s->token.ptr;
/* optional chaining */
if (next_token(s))
@@ -27971,7 +28245,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;
@@ -27981,6 +28255,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;
@@ -27989,6 +28264,7 @@ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
m->promise = JS_UNDEFINED;
m->resolving_funcs[0] = JS_UNDEFINED;
m->resolving_funcs[1] = JS_UNDEFINED;
+ m->private_value = JS_UNDEFINED;
list_add_tail(&m->link, &ctx->loaded_modules);
return m;
}
@@ -27998,6 +28274,11 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
{
int i;
+ for(i = 0; i < m->req_module_entries_count; i++) {
+ JSReqModuleEntry *rme = &m->req_module_entries[i];
+ JS_MarkValue(rt, rme->attributes, mark_func);
+ }
+
for(i = 0; i < m->export_entries_count; i++) {
JSExportEntry *me = &m->export_entries[i];
if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
@@ -28013,61 +28294,65 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
JS_MarkValue(rt, m->promise, mark_func);
JS_MarkValue(rt, m->resolving_funcs[0], mark_func);
JS_MarkValue(rt, m->resolving_funcs[1], mark_func);
+ 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_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]);
- 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,
JSAtom module_name)
{
JSReqModuleEntry *rme;
- int i;
-
- /* no need to add the module request if it is already present */
- for(i = 0; i < m->req_module_entries_count; i++) {
- rme = &m->req_module_entries[i];
- if (rme->module_name == module_name)
- return i;
- }
if (js_resize_array(ctx, (void **)&m->req_module_entries,
sizeof(JSReqModuleEntry),
@@ -28077,7 +28362,8 @@ static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
rme = &m->req_module_entries[m->req_module_entries_count++];
rme->module_name = JS_DupAtom(ctx, module_name);
rme->module = NULL;
- return i;
+ rme->attributes = JS_UNDEFINED;
+ return m->req_module_entries_count - 1;
}
static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m,
@@ -28157,6 +28443,8 @@ JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
if (name == JS_ATOM_NULL)
return NULL;
m = js_new_module_def(ctx, name);
+ if (!m)
+ return NULL;
m->init_func = func;
return m;
}
@@ -28196,12 +28484,38 @@ int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
return -1;
}
+int JS_SetModulePrivateValue(JSContext *ctx, JSModuleDef *m, JSValue val)
+{
+ set_value(ctx, &m->private_value, val);
+ return 0;
+}
+
+JSValue JS_GetModulePrivateValue(JSContext *ctx, JSModuleDef *m)
+{
+ return JS_DupValue(ctx, m->private_value);
+}
+
void JS_SetModuleLoaderFunc(JSRuntime *rt,
JSModuleNormalizeFunc *module_normalize,
JSModuleLoaderFunc *module_loader, void *opaque)
{
rt->module_normalize_func = module_normalize;
- rt->module_loader_func = module_loader;
+ rt->module_loader_has_attr = FALSE;
+ rt->u.module_loader_func = module_loader;
+ rt->module_check_attrs = NULL;
+ rt->module_loader_opaque = opaque;
+}
+
+void JS_SetModuleLoaderFunc2(JSRuntime *rt,
+ JSModuleNormalizeFunc *module_normalize,
+ JSModuleLoaderFunc2 *module_loader,
+ JSModuleCheckSupportedImportAttributes *module_check_attrs,
+ void *opaque)
+{
+ rt->module_normalize_func = module_normalize;
+ rt->module_loader_has_attr = TRUE;
+ rt->u.module_loader_func2 = module_loader;
+ rt->module_check_attrs = module_check_attrs;
rt->module_loader_opaque = opaque;
}
@@ -28282,7 +28596,8 @@ static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name)
/* return NULL in case of exception (e.g. module could not be loaded) */
static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
const char *base_cname,
- const char *cname1)
+ const char *cname1,
+ JSValueConst attributes)
{
JSRuntime *rt = ctx->rt;
JSModuleDef *m;
@@ -28315,22 +28630,26 @@ static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
JS_FreeAtom(ctx, module_name);
/* load the module */
- if (!rt->module_loader_func) {
+ if (!rt->u.module_loader_func) {
/* XXX: use a syntax error ? */
JS_ThrowReferenceError(ctx, "could not load module '%s'",
cname);
js_free(ctx, cname);
return NULL;
}
-
- m = rt->module_loader_func(ctx, cname, rt->module_loader_opaque);
+ if (rt->module_loader_has_attr) {
+ m = rt->u.module_loader_func2(ctx, cname, rt->module_loader_opaque, attributes);
+ } else {
+ m = rt->u.module_loader_func(ctx, cname, rt->module_loader_opaque);
+ }
js_free(ctx, cname);
return m;
}
static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
- JSAtom base_module_name,
- JSAtom module_name1)
+ JSAtom base_module_name,
+ JSAtom module_name1,
+ JSValueConst attributes)
{
const char *base_cname, *cname;
JSModuleDef *m;
@@ -28343,7 +28662,7 @@ static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
JS_FreeCString(ctx, base_cname);
return NULL;
}
- m = js_host_resolve_imported_module(ctx, base_cname, cname);
+ m = js_host_resolve_imported_module(ctx, base_cname, cname, attributes);
JS_FreeCString(ctx, base_cname);
JS_FreeCString(ctx, cname);
return m;
@@ -28805,7 +29124,8 @@ static int js_resolve_module(JSContext *ctx, JSModuleDef *m)
for(i = 0; i < m->req_module_entries_count; i++) {
JSReqModuleEntry *rme = &m->req_module_entries[i];
m1 = js_host_resolve_imported_module_atom(ctx, m->module_name,
- rme->module_name);
+ rme->module_name,
+ rme->attributes);
if (!m1)
return -1;
rme->module = m1;
@@ -29282,14 +29602,15 @@ static JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val,
static void JS_LoadModuleInternal(JSContext *ctx, const char *basename,
const char *filename,
- JSValueConst *resolving_funcs)
+ JSValueConst *resolving_funcs,
+ JSValueConst attributes)
{
JSValue evaluate_promise;
JSModuleDef *m;
JSValue ret, err, func_obj, evaluate_resolving_funcs[2];
JSValueConst func_data[3];
- m = js_host_resolve_imported_module(ctx, basename, filename);
+ m = js_host_resolve_imported_module(ctx, basename, filename, attributes);
if (!m)
goto fail;
@@ -29336,7 +29657,7 @@ JSValue JS_LoadModule(JSContext *ctx, const char *basename,
if (JS_IsException(promise))
return JS_EXCEPTION;
JS_LoadModuleInternal(ctx, basename, filename,
- (JSValueConst *)resolving_funcs);
+ (JSValueConst *)resolving_funcs, JS_UNDEFINED);
JS_FreeValue(ctx, resolving_funcs[0]);
JS_FreeValue(ctx, resolving_funcs[1]);
return promise;
@@ -29348,6 +29669,7 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
JSValueConst *resolving_funcs = argv;
JSValueConst basename_val = argv[2];
JSValueConst specifier = argv[3];
+ JSValueConst attributes = argv[4];
const char *basename = NULL, *filename;
JSValue ret, err;
@@ -29364,7 +29686,7 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
goto exception;
JS_LoadModuleInternal(ctx, basename, filename,
- resolving_funcs);
+ resolving_funcs, attributes);
JS_FreeCString(ctx, filename);
JS_FreeCString(ctx, basename);
return JS_UNDEFINED;
@@ -29378,11 +29700,12 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
return JS_UNDEFINED;
}
-static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
+static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options)
{
JSAtom basename;
- JSValue promise, resolving_funcs[2], basename_val;
- JSValueConst args[4];
+ JSValue promise, resolving_funcs[2], basename_val, err, ret;
+ JSValue specifier_str = JS_UNDEFINED, attributes = JS_UNDEFINED, attributes_obj = JS_UNDEFINED;
+ JSValueConst args[5];
basename = JS_GetScriptOrModuleName(ctx, 0);
if (basename == JS_ATOM_NULL)
@@ -29399,19 +29722,82 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
return promise;
}
+ /* the string conversion must occur here */
+ specifier_str = JS_ToString(ctx, specifier);
+ if (JS_IsException(specifier_str))
+ goto exception;
+
+ if (!JS_IsUndefined(options)) {
+ if (!JS_IsObject(options)) {
+ JS_ThrowTypeError(ctx, "options must be an object");
+ goto exception;
+ }
+ attributes_obj = JS_GetProperty(ctx, options, JS_ATOM_with);
+ if (JS_IsException(attributes_obj))
+ goto exception;
+ if (!JS_IsUndefined(attributes_obj)) {
+ JSPropertyEnum *atoms;
+ uint32_t atoms_len, i;
+ JSValue val;
+
+ if (!JS_IsObject(attributes_obj)) {
+ JS_ThrowTypeError(ctx, "options.with must be an object");
+ goto exception;
+ }
+ attributes = JS_NewObjectProto(ctx, JS_NULL);
+ if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &atoms_len, JS_VALUE_GET_OBJ(attributes_obj),
+ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
+ goto exception;
+ }
+ for(i = 0; i < atoms_len; i++) {
+ val = JS_GetProperty(ctx, attributes_obj, atoms[i].atom);
+ if (JS_IsException(val))
+ goto exception1;
+ if (!JS_IsString(val)) {
+ JS_FreeValue(ctx, val);
+ JS_ThrowTypeError(ctx, "module attribute values must be strings");
+ goto exception1;
+ }
+ if (JS_DefinePropertyValue(ctx, attributes, atoms[i].atom, val,
+ JS_PROP_C_W_E) < 0) {
+ exception1:
+ JS_FreePropertyEnum(ctx, atoms, atoms_len);
+ goto exception;
+ }
+ }
+ JS_FreePropertyEnum(ctx, atoms, atoms_len);
+ if (ctx->rt->module_check_attrs &&
+ ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, attributes) < 0) {
+ goto exception;
+ }
+ JS_FreeValue(ctx, attributes_obj);
+ }
+ }
+
args[0] = resolving_funcs[0];
args[1] = resolving_funcs[1];
args[2] = basename_val;
- args[3] = specifier;
-
+ args[3] = specifier_str;
+ args[4] = attributes;
+
/* cannot run JS_LoadModuleInternal synchronously because it would
cause an unexpected recursion in js_evaluate_module() */
- JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args);
-
+ JS_EnqueueJob(ctx, js_dynamic_import_job, 5, args);
+ done:
JS_FreeValue(ctx, basename_val);
JS_FreeValue(ctx, resolving_funcs[0]);
JS_FreeValue(ctx, resolving_funcs[1]);
+ JS_FreeValue(ctx, specifier_str);
+ JS_FreeValue(ctx, attributes);
return promise;
+ exception:
+ JS_FreeValue(ctx, attributes_obj);
+ err = JS_GetException(ctx);
+ ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
+ 1, (JSValueConst *)&err);
+ JS_FreeValue(ctx, ret);
+ JS_FreeValue(ctx, err);
+ goto done;
}
static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m)
@@ -29488,6 +29874,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)
@@ -29496,6 +29890,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);
@@ -29511,6 +29908,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];
@@ -29537,6 +29935,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;
@@ -29562,6 +29963,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) {
@@ -29576,6 +29980,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);
}
}
@@ -29588,6 +29993,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;
@@ -29607,6 +30015,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)
@@ -29646,19 +30057,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) {
@@ -29759,6 +30167,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);
@@ -29791,6 +30202,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);
@@ -29807,27 +30221,109 @@ static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
return JS_DupValue(ctx, m->promise);
}
-static __exception JSAtom js_parse_from_clause(JSParseState *s)
+static __exception int js_parse_with_clause(JSParseState *s, JSReqModuleEntry *rme)
+{
+ JSContext *ctx = s->ctx;
+ JSAtom key;
+ int ret;
+ const uint8_t *key_token_ptr;
+
+ if (next_token(s))
+ return -1;
+ if (js_parse_expect(s, '{'))
+ return -1;
+ while (s->token.val != '}') {
+ key_token_ptr = s->token.ptr;
+ if (s->token.val == TOK_STRING) {
+ key = JS_ValueToAtom(ctx, s->token.u.str.str);
+ if (key == JS_ATOM_NULL)
+ return -1;
+ } else {
+ if (!token_is_ident(s->token.val)) {
+ js_parse_error(s, "identifier expected");
+ return -1;
+ }
+ key = JS_DupAtom(ctx, s->token.u.ident.atom);
+ }
+ if (next_token(s))
+ return -1;
+ if (js_parse_expect(s, ':')) {
+ JS_FreeAtom(ctx, key);
+ return -1;
+ }
+ if (s->token.val != TOK_STRING) {
+ js_parse_error_pos(s, key_token_ptr, "string expected");
+ return -1;
+ }
+ if (JS_IsUndefined(rme->attributes)) {
+ JSValue attributes = JS_NewObjectProto(ctx, JS_NULL);
+ if (JS_IsException(attributes)) {
+ JS_FreeAtom(ctx, key);
+ return -1;
+ }
+ rme->attributes = attributes;
+ }
+ ret = JS_HasProperty(ctx, rme->attributes, key);
+ if (ret != 0) {
+ JS_FreeAtom(ctx, key);
+ if (ret < 0)
+ return -1;
+ else
+ return js_parse_error(s, "duplicate with key");
+ }
+ ret = JS_DefinePropertyValue(ctx, rme->attributes, key,
+ JS_DupValue(ctx, s->token.u.str.str), JS_PROP_C_W_E);
+ JS_FreeAtom(ctx, key);
+ if (ret < 0)
+ return -1;
+ if (next_token(s))
+ return -1;
+ if (s->token.val != ',')
+ break;
+ if (next_token(s))
+ return -1;
+ }
+ if (!JS_IsUndefined(rme->attributes) &&
+ ctx->rt->module_check_attrs &&
+ ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, rme->attributes) < 0) {
+ return -1;
+ }
+ return js_parse_expect(s, '}');
+}
+
+/* return the module index in m->req_module_entries[] or < 0 if error */
+static __exception int js_parse_from_clause(JSParseState *s, JSModuleDef *m)
{
JSAtom module_name;
+ int idx;
+
if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
js_parse_error(s, "from clause expected");
- return JS_ATOM_NULL;
+ return -1;
}
if (next_token(s))
- return JS_ATOM_NULL;
+ return -1;
if (s->token.val != TOK_STRING) {
js_parse_error(s, "string expected");
- return JS_ATOM_NULL;
+ return -1;
}
module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
if (module_name == JS_ATOM_NULL)
- return JS_ATOM_NULL;
+ return -1;
if (next_token(s)) {
JS_FreeAtom(s->ctx, module_name);
- return JS_ATOM_NULL;
+ return -1;
+ }
+
+ idx = add_req_module_entry(s->ctx, m, module_name);
+ JS_FreeAtom(s->ctx, module_name);
+ if (idx < 0)
+ return -1;
+ if (s->token.val == TOK_WITH) {
+ if (js_parse_with_clause(s, &m->req_module_entries[idx]))
+ return -1;
}
- return module_name;
+ return idx;
}
static __exception int js_parse_export(JSParseState *s)
@@ -29836,7 +30332,6 @@ static __exception int js_parse_export(JSParseState *s)
JSModuleDef *m = s->cur_func->module;
JSAtom local_name, export_name;
int first_export, idx, i, tok;
- JSAtom module_name;
JSExportEntry *me;
if (next_token(s))
@@ -29911,11 +30406,7 @@ static __exception int js_parse_export(JSParseState *s)
if (js_parse_expect(s, '}'))
return -1;
if (token_is_pseudo_keyword(s, JS_ATOM_from)) {
- module_name = js_parse_from_clause(s);
- if (module_name == JS_ATOM_NULL)
- return -1;
- idx = add_req_module_entry(ctx, m, module_name);
- JS_FreeAtom(ctx, module_name);
+ idx = js_parse_from_clause(s, m);
if (idx < 0)
return -1;
for(i = first_export; i < m->export_entries_count; i++) {
@@ -29937,11 +30428,7 @@ static __exception int js_parse_export(JSParseState *s)
export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
if (next_token(s))
goto fail1;
- module_name = js_parse_from_clause(s);
- if (module_name == JS_ATOM_NULL)
- goto fail1;
- idx = add_req_module_entry(ctx, m, module_name);
- JS_FreeAtom(ctx, module_name);
+ idx = js_parse_from_clause(s, m);
if (idx < 0)
goto fail1;
me = add_export_entry(s, m, JS_ATOM__star_, export_name,
@@ -29951,11 +30438,7 @@ static __exception int js_parse_export(JSParseState *s)
return -1;
me->u.req_module_idx = idx;
} else {
- module_name = js_parse_from_clause(s);
- if (module_name == JS_ATOM_NULL)
- return -1;
- idx = add_req_module_entry(ctx, m, module_name);
- JS_FreeAtom(ctx, module_name);
+ idx = js_parse_from_clause(s, m);
if (idx < 0)
return -1;
if (add_star_export_entry(ctx, m, idx) < 0)
@@ -30061,6 +30544,14 @@ static __exception int js_parse_import(JSParseState *s)
JS_FreeAtom(ctx, module_name);
return -1;
}
+ idx = add_req_module_entry(ctx, m, module_name);
+ JS_FreeAtom(ctx, module_name);
+ if (idx < 0)
+ return -1;
+ if (s->token.val == TOK_WITH) {
+ if (js_parse_with_clause(s, &m->req_module_entries[idx]))
+ return -1;
+ }
} else {
if (s->token.val == TOK_IDENT) {
if (s->token.u.ident.is_reserved) {
@@ -30159,14 +30650,10 @@ static __exception int js_parse_import(JSParseState *s)
return -1;
}
end_import_clause:
- module_name = js_parse_from_clause(s);
- if (module_name == JS_ATOM_NULL)
+ idx = js_parse_from_clause(s, m);
+ if (idx < 0)
return -1;
}
- idx = add_req_module_entry(ctx, m, module_name);
- JS_FreeAtom(ctx, module_name);
- if (idx < 0)
- return -1;
for(i = first_import; i < m->import_entries_count; i++)
m->import_entries[i].req_module_idx = idx;
@@ -30289,6 +30776,8 @@ static void free_bytecode_atoms(JSRuntime *rt,
case OP_FMT_atom_u16:
case OP_FMT_atom_label_u8:
case OP_FMT_atom_label_u16:
+ if ((pos + 1 + 4) > bc_len)
+ break; /* may happen if there is not enough memory when emiting bytecode */
atom = get_u32(bc_buf + pos + 1);
JS_FreeAtomRT(rt, atom);
break;
@@ -31078,7 +31567,13 @@ static void var_object_test(JSContext *ctx, JSFunctionDef *s,
{
dbuf_putc(bc, get_with_scope_opcode(op));
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- *plabel_done = new_label_fd(s, *plabel_done);
+ if (*plabel_done < 0) {
+ *plabel_done = new_label_fd(s);
+ if (*plabel_done < 0) {
+ dbuf_set_error(bc);
+ return;
+ }
+ }
dbuf_put_u32(bc, *plabel_done);
dbuf_putc(bc, is_with);
update_label(s, *plabel_done, 1);
@@ -32123,8 +32618,11 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy
evaluating the module so that the exported functions are
visible if there are cyclic module references */
if (s->module) {
- label_next = new_label_fd(s, -1);
-
+ label_next = new_label_fd(s);
+ if (label_next < 0) {
+ dbuf_set_error(bc);
+ return;
+ }
/* if 'this' is true, initialize the global variables and return */
dbuf_putc(bc, OP_push_this);
dbuf_putc(bc, OP_if_false);
@@ -34935,7 +35433,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
push_scope(s); /* enter body scope */
fd->body_scope = fd->scope_level;
- if (s->token.val == TOK_ARROW) {
+ if (s->token.val == TOK_ARROW && func_type == JS_PARSE_FUNC_ARROW) {
if (next_token(s))
goto fail;
@@ -35345,7 +35843,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;
}
@@ -35974,6 +36472,8 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
for(i = 0; i < m->req_module_entries_count; i++) {
JSReqModuleEntry *rme = &m->req_module_entries[i];
bc_put_atom(s, rme->module_name);
+ if (JS_WriteObjectRec(s, rme->attributes))
+ goto fail;
}
bc_put_leb128(s, m->export_entries_count);
@@ -36973,8 +37473,13 @@ static JSValue JS_ReadModule(BCReaderState *s)
goto fail;
for(i = 0; i < m->req_module_entries_count; i++) {
JSReqModuleEntry *rme = &m->req_module_entries[i];
+ JSValue val;
if (bc_get_atom(s, &rme->module_name))
goto fail;
+ val = JS_ReadObjectRec(s);
+ if (JS_IsException(val))
+ goto fail;
+ rme->attributes = val;
}
}
@@ -37050,7 +37555,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;
}
@@ -37642,17 +38147,22 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
return 0;
}
-void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
- const JSCFunctionListEntry *tab, int len)
+int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
+ const JSCFunctionListEntry *tab, int len)
{
- int i;
+ int i, ret;
for (i = 0; i < len; i++) {
const JSCFunctionListEntry *e = &tab[i];
JSAtom atom = find_atom(ctx, e->name);
- JS_InstantiateFunctionListItem(ctx, obj, atom, e);
+ if (atom == JS_ATOM_NULL)
+ return -1;
+ ret = JS_InstantiateFunctionListItem(ctx, obj, atom, e);
JS_FreeAtom(ctx, atom);
+ if (ret)
+ return -1;
}
+ return 0;
}
int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
@@ -37970,7 +38480,7 @@ static __exception int JS_ObjectDefineProperties(JSContext *ctx,
ret = 0;
exception:
- js_free_prop_enum(ctx, atoms, len);
+ JS_FreePropertyEnum(ctx, atoms, len);
JS_FreeValue(ctx, props);
JS_FreeValue(ctx, desc);
return ret;
@@ -38241,12 +38751,12 @@ static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst
goto exception;
}
}
- js_free_prop_enum(ctx, props, len);
+ JS_FreePropertyEnum(ctx, props, len);
JS_FreeValue(ctx, obj);
return r;
exception:
- js_free_prop_enum(ctx, props, len);
+ JS_FreePropertyEnum(ctx, props, len);
JS_FreeValue(ctx, obj);
JS_FreeValue(ctx, r);
return JS_EXCEPTION;
@@ -38326,7 +38836,7 @@ exception:
JS_FreeValue(ctx, r);
r = JS_EXCEPTION;
done:
- js_free_prop_enum(ctx, atoms, len);
+ JS_FreePropertyEnum(ctx, atoms, len);
JS_FreeValue(ctx, obj);
return r;
}
@@ -38587,11 +39097,11 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)
goto exception;
}
- js_free_prop_enum(ctx, props, len);
+ JS_FreePropertyEnum(ctx, props, len);
return JS_DupValue(ctx, obj);
exception:
- js_free_prop_enum(ctx, props, len);
+ JS_FreePropertyEnum(ctx, props, len);
return JS_EXCEPTION;
}
@@ -38633,11 +39143,11 @@ static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
res ^= 1;
done:
- js_free_prop_enum(ctx, props, len);
+ JS_FreePropertyEnum(ctx, props, len);
return JS_NewBool(ctx, res);
exception:
- js_free_prop_enum(ctx, props, len);
+ JS_FreePropertyEnum(ctx, props, len);
return JS_EXCEPTION;
}
@@ -39535,6 +40045,16 @@ static const JSCFunctionListEntry js_error_proto_funcs[] = {
JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
};
+static JSValue js_error_isError(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return JS_NewBool(ctx, JS_IsError(ctx, argv[0]));
+}
+
+static const JSCFunctionListEntry js_error_funcs[] = {
+ JS_CFUNC_DEF("isError", 1, js_error_isError),
+};
+
/* AggregateError */
/* used by C code. */
@@ -44070,9 +44590,13 @@ static int getTimezoneOffset(int64_t time)
time_t gm_ti, loc_ti;
tm = gmtime(&ti);
+ if (!tm)
+ return 0;
gm_ti = mktime(tm);
tm = localtime(&ti);
+ if (!tm)
+ return 0;
loc_ti = mktime(tm);
res = (gm_ti - loc_ti) / 60;
@@ -45044,7 +45568,7 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(matchStr))
goto exception;
isEmpty = JS_IsEmptyString(matchStr);
- if (JS_SetPropertyInt64(ctx, A, n++, matchStr) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, A, n++, matchStr, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
if (isEmpty) {
int64_t thisIndex, nextIndex;
@@ -45862,6 +46386,12 @@ static JSValue json_parse_value(JSParseState *s)
val = JS_NewBool(ctx, s->token.u.ident.atom == JS_ATOM_true);
} else if (s->token.u.ident.atom == JS_ATOM_null) {
val = JS_NULL;
+ } else if (s->token.u.ident.atom == JS_ATOM_NaN && s->ext_json) {
+ /* Note: json5 identifier handling is ambiguous e.g. is
+ '{ NaN: 1 }' a valid JSON5 production ? */
+ val = JS_NewFloat64(s->ctx, NAN);
+ } else if (s->token.u.ident.atom == JS_ATOM_Infinity && s->ext_json) {
+ val = JS_NewFloat64(s->ctx, INFINITY);
} else {
goto def_token;
}
@@ -45966,7 +46496,7 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
goto fail;
}
}
- js_free_prop_enum(ctx, atoms, len);
+ JS_FreePropertyEnum(ctx, atoms, len);
atoms = NULL;
name_val = JS_AtomToValue(ctx, name);
if (JS_IsException(name_val))
@@ -45978,7 +46508,7 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
JS_FreeValue(ctx, val);
return res;
fail:
- js_free_prop_enum(ctx, atoms, len);
+ JS_FreePropertyEnum(ctx, atoms, len);
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
@@ -47352,14 +47882,14 @@ static int js_proxy_get_own_property_names(JSContext *ctx,
}
}
- js_free_prop_enum(ctx, tab2, len2);
+ JS_FreePropertyEnum(ctx, tab2, len2);
JS_FreeValue(ctx, prop_array);
*ptab = tab;
*plen = len;
return 0;
fail:
- js_free_prop_enum(ctx, tab2, len2);
- js_free_prop_enum(ctx, tab, len);
+ JS_FreePropertyEnum(ctx, tab2, len2);
+ JS_FreePropertyEnum(ctx, tab, len);
JS_FreeValue(ctx, prop_array);
return -1;
}
@@ -51826,6 +52356,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
"Error", 1, JS_CFUNC_constructor_or_func_magic, -1);
JS_NewGlobalCConstructor2(ctx, obj1,
"Error", ctx->class_proto[JS_CLASS_ERROR]);
+ JS_SetPropertyFunctionList(ctx, obj1, js_error_funcs, countof(js_error_funcs));
/* Used to squelch a -Wcast-function-type warning. */
JSCFunctionType ft = { .generic_magic = js_error_constructor };
@@ -53566,7 +54097,8 @@ static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValueConst args[4];
- JSValue arr, byteOffset, ta_buffer;
+ JSValue arr, ta_buffer;
+ JSTypedArray *ta;
JSObject *p;
int len, start, final, count, shift, offset;
@@ -53583,12 +54115,10 @@ static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val,
goto exception;
}
count = max_int(final - start, 0);
- byteOffset = js_typed_array_get_byteOffset(ctx, this_val, 0);
- if (JS_IsException(byteOffset))
- goto exception;
shift = typed_array_size_log2(p->class_id);
- offset = JS_VALUE_GET_INT(byteOffset) + (start << shift);
- JS_FreeValue(ctx, byteOffset);
+ 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;
@@ -55172,7 +55702,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;
@@ -55189,6 +55719,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);
}
@@ -55205,6 +55736,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);
}
}
@@ -55230,7 +55762,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);
@@ -55265,7 +55797,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/quickjs.h b/quickjs.h
index 45f9c08..4570c6d 100644
--- a/quickjs.h
+++ b/quickjs.h
@@ -456,7 +456,11 @@ void JS_FreeAtom(JSContext *ctx, JSAtom v);
void JS_FreeAtomRT(JSRuntime *rt, JSAtom v);
JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom);
JSValue JS_AtomToString(JSContext *ctx, JSAtom atom);
-const char *JS_AtomToCString(JSContext *ctx, JSAtom atom);
+const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom);
+static inline const char *JS_AtomToCString(JSContext *ctx, JSAtom atom)
+{
+ return JS_AtomToCStringLen(ctx, NULL, atom);
+}
JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val);
/* object class support */
@@ -805,6 +809,8 @@ JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val);
int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
uint32_t *plen, JSValueConst obj, int flags);
+void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab,
+ uint32_t len);
int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
JSValueConst obj, JSAtom prop);
@@ -930,12 +936,25 @@ typedef char *JSModuleNormalizeFunc(JSContext *ctx,
const char *module_name, void *opaque);
typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx,
const char *module_name, void *opaque);
-
+typedef JSModuleDef *JSModuleLoaderFunc2(JSContext *ctx,
+ const char *module_name, void *opaque,
+ JSValueConst attributes);
+/* return -1 if exception, 0 if OK */
+typedef int JSModuleCheckSupportedImportAttributes(JSContext *ctx, void *opaque,
+ JSValueConst attributes);
+
/* module_normalize = NULL is allowed and invokes the default module
filename normalizer */
void JS_SetModuleLoaderFunc(JSRuntime *rt,
JSModuleNormalizeFunc *module_normalize,
JSModuleLoaderFunc *module_loader, void *opaque);
+/* same as JS_SetModuleLoaderFunc but with attributes. if
+ module_check_attrs = NULL, no attribute checking is done. */
+void JS_SetModuleLoaderFunc2(JSRuntime *rt,
+ JSModuleNormalizeFunc *module_normalize,
+ JSModuleLoaderFunc2 *module_loader,
+ JSModuleCheckSupportedImportAttributes *module_check_attrs,
+ void *opaque);
/* return the import.meta object of a module */
JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m);
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m);
@@ -1094,9 +1113,9 @@ typedef struct JSCFunctionListEntry {
#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } }
#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } }
-void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
- const JSCFunctionListEntry *tab,
- int len);
+int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
+ const JSCFunctionListEntry *tab,
+ int len);
/* C module definition */
@@ -1113,7 +1132,10 @@ int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
JSValue val);
int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
const JSCFunctionListEntry *tab, int len);
-
+/* associate a JSValue to a C module */
+int JS_SetModulePrivateValue(JSContext *ctx, JSModuleDef *m, JSValue val);
+JSValue JS_GetModulePrivateValue(JSContext *ctx, JSModuleDef *m);
+
/* debug value output */
typedef struct {
diff --git a/run-test262.c b/run-test262.c
index 3da79a0..ef16025 100644
--- a/run-test262.c
+++ b/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;
@@ -836,13 +835,21 @@ static char *load_file(const char *filename, size_t *lenp)
return buf;
}
+static int json_module_init_test(JSContext *ctx, JSModuleDef *m)
+{
+ JSValue val;
+ val = JS_GetModulePrivateValue(ctx, m);
+ JS_SetModuleExport(ctx, m, "default", val);
+ return 0;
+}
+
static JSModuleDef *js_module_loader_test(JSContext *ctx,
- const char *module_name, void *opaque)
+ const char *module_name, void *opaque,
+ JSValueConst attributes)
{
size_t buf_len;
uint8_t *buf;
JSModuleDef *m;
- JSValue func_val;
char *filename, *slash, path[1024];
// interpret import("bar.js") from path/to/foo.js as
@@ -864,15 +871,33 @@ static JSModuleDef *js_module_loader_test(JSContext *ctx,
return NULL;
}
- /* compile the module */
- func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
- JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
- js_free(ctx, buf);
- if (JS_IsException(func_val))
- return NULL;
- /* the module is already referenced, so we must free it */
- m = JS_VALUE_GET_PTR(func_val);
- JS_FreeValue(ctx, func_val);
+ if (js_module_test_json(ctx, attributes) == 1) {
+ /* compile as JSON */
+ JSValue val;
+ val = JS_ParseJSON(ctx, (char *)buf, buf_len, module_name);
+ js_free(ctx, buf);
+ if (JS_IsException(val))
+ return NULL;
+ m = JS_NewCModule(ctx, module_name, json_module_init_test);
+ if (!m) {
+ JS_FreeValue(ctx, val);
+ return NULL;
+ }
+ /* only export the "default" symbol which will contain the JSON object */
+ JS_AddModuleExport(ctx, m, "default");
+ JS_SetModulePrivateValue(ctx, m, val);
+ } else {
+ JSValue func_val;
+ /* compile the module */
+ func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
+ JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
+ js_free(ctx, buf);
+ if (JS_IsException(func_val))
+ return NULL;
+ /* the module is already referenced, so we must free it */
+ m = JS_VALUE_GET_PTR(func_val);
+ JS_FreeValue(ctx, func_val);
+ }
return m;
}
@@ -1244,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;
@@ -1587,7 +1611,7 @@ int run_test_buf(const char *filename, const char *harness, namelist_t *ip,
JS_SetCanBlock(rt, can_block);
/* loader for ES6 modules */
- JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, (void *)filename);
+ JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader_test, NULL, (void *)filename);
add_helpers(ctx);
@@ -1888,7 +1912,7 @@ int run_test262_harness_test(const char *filename, BOOL is_module)
JS_SetCanBlock(rt, can_block);
/* loader for ES6 modules */
- JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, (void *)filename);
+ JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader_test, NULL, (void *)filename);
add_helpers(ctx);
@@ -1912,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/test262.conf b/test262.conf
index 02df380..c099f2f 100644
--- a/test262.conf
+++ b/test262.conf
@@ -103,7 +103,7 @@ destructuring-assignment
destructuring-binding
dynamic-import
error-cause
-Error.isError=skip
+Error.isError
explicit-resource-management=skip
exponentiation
export-star-as-namespace-from-module
@@ -116,9 +116,7 @@ for-of
generators
globalThis
hashbang
-host-gc-required=skip
-import-assertions=skip
-import-attributes=skip
+import-attributes
import-defer=skip
import.meta
Int16Array
@@ -144,7 +142,7 @@ Intl.Segmenter=skip
IsHTMLDDA
iterator-helpers=skip
iterator-sequencing=skip
-json-modules=skip
+json-modules
json-parse-with-source=skip
json-superset
legacy-regexp=skip
@@ -230,6 +228,7 @@ Uint32Array
Uint8Array
uint8array-base64=skip
Uint8ClampedArray
+upsert=skip
WeakMap
WeakRef
WeakSet
@@ -323,12 +322,23 @@ test262/test/staging/sm/Function/function-toString-builtin-name.js
test262/test/staging/sm/extensions/arguments-property-access-in-function.js
test262/test/staging/sm/extensions/function-caller-skips-eval-frames.js
test262/test/staging/sm/extensions/function-properties.js
+test262/test/staging/sm/regress/regress-577648-1.js
+test262/test/staging/sm/regress/regress-577648-2.js
+test262/test/staging/sm/regress/regress-584355.js
+test262/test/staging/sm/regress/regress-586482-1.js
+test262/test/staging/sm/regress/regress-586482-2.js
+test262/test/staging/sm/regress/regress-586482-3.js
+test262/test/staging/sm/regress/regress-586482-4.js
+test262/test/staging/sm/regress/regress-699682.js
+
# RegExp toSource not fully compliant
test262/test/staging/sm/RegExp/toString.js
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/test262_errors.txt b/test262_errors.txt
index e8cd853..de5f30a 100644
--- a/test262_errors.txt
+++ b/test262_errors.txt
@@ -1,4 +1,5 @@
-test262/test/language/module-code/top-level-await/module-graphs-does-not-hang.js:10: TypeError: $DONE() not called
+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/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
test262/test/staging/sm/Date/constructor-convert-all-arguments.js:75: Test262Error: index undefined: expected 42, got Error: didn't throw Expected SameValue(«Error: didn't throw», «42») to be true
test262/test/staging/sm/Date/non-iso.js:76: Test262Error: Expected SameValue(«NaN», «-40071559730000») to be true
@@ -7,38 +8,30 @@ 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/JSON/parse-number-syntax.js:39: Test262Error: parsing string <1.> threw a non-SyntaxError exception: Test262Error: string <1.> shouldn't have parsed as JSON Expected SameValue(«false», «true») to be true Expected SameValue(«true», «false») to be true
-test262/test/staging/sm/JSON/parse-syntax-errors-02.js:51: Test262Error: parsing string <["Illegal backslash escape: \x15"]> threw a non-SyntaxError exception: Test262Error: string <["Illegal backslash escape: \x15"]> shouldn't have parsed as JSON Expected SameValue(«false», «true») to be true Expected SameValue(«true», «false») to be true
-test262/test/staging/sm/Math/cbrt-approx.js:26: Error: got 1.39561242508609, expected a number near 1.3956124250860895 (relative error: 2)
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/String/match-defines-match-elements.js:52: Test262Error: Expected SameValue(«true», «false») 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
test262/test/staging/sm/TypedArray/set-detached.js:112: RangeError: invalid array length
test262/test/staging/sm/TypedArray/sort_modifications.js:12: Test262Error: Int8Array at index 0 for size 4 Expected SameValue(«0», «1») to be true
-test262/test/staging/sm/TypedArray/subarray.js:15: Test262Error: Expected SameValue(«0», «1») to be true
test262/test/staging/sm/async-functions/async-contains-unicode-escape.js:45: Error: Assertion failed: expected exception SyntaxError, no exception thrown
test262/test/staging/sm/async-functions/await-error.js:12: Test262Error: Expected SameValue(«false», «true») to be true
test262/test/staging/sm/async-functions/await-in-arrow-parameters.js:33: Error: Assertion failed: expected exception SyntaxError, no exception thrown - AsyncFunction:(a = (b = await/r/g) => {}) => {}
test262/test/staging/sm/class/boundFunctionSubclassing.js:12: Test262Error: Expected SameValue(«false», «true») to be true
test262/test/staging/sm/class/compPropNames.js:26: Error: Expected syntax error: ({[1, 2]: 3})
-test262/test/staging/sm/class/methDefn.js:26: Error: Expected syntax error: b = {a() => 0}
test262/test/staging/sm/class/strictExecution.js:32: Error: Assertion failed: expected exception TypeError, no exception thrown
test262/test/staging/sm/class/superPropOrdering.js:83: Error: Assertion failed: expected exception TypeError, no exception thrown
-test262/test/staging/sm/expressions/optional-chain.js:25: Error: Assertion failed: expected exception SyntaxError, no exception thrown
test262/test/staging/sm/expressions/short-circuit-compound-assignment-const.js:97: TypeError: 'a' is read-only
test262/test/staging/sm/expressions/short-circuit-compound-assignment-tdz.js:23: Error: Assertion failed: expected exception ReferenceError, got TypeError: 'a' is read-only
test262/test/staging/sm/extensions/TypedArray-set-object-funky-length-detaches.js:55: RangeError: invalid array length
-test262/test/staging/sm/extensions/regress-469625-01.js:16: Test262Error: TM: Array prototype and expression closures Expected SameValue(«"TypeError: [].__proto__ is not a function"», «"TypeError: not a function"») to be true
test262/test/staging/sm/generators/syntax.js:30: Error: Assertion failed: expected SyntaxError, but no exception thrown - function* g() { (function* yield() {}); }
test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-arguments.js:14: Test262Error: Expected SameValue(«"object"», «"function"») to be true
test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-eval.js:12: Test262Error: Expected SameValue(«"outer-gouter-geval-gtruefalseq"», «"outer-geval-gwith-gtruefalseq"») to be true
@@ -47,15 +40,7 @@ test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-notap
test262/test/staging/sm/lexical-environment/block-scoped-functions-deprecated-redecl.js:23: Test262Error: Expected SameValue(«3», «4») to be true
test262/test/staging/sm/lexical-environment/var-in-catch-body-annex-b-eval.js:17: Test262Error: Expected SameValue(«"g"», «"global-x"») to be true
test262/test/staging/sm/object/defineProperties-order.js:14: Test262Error: Expected SameValue(«"ownKeys,getOwnPropertyDescriptor,getOwnPropertyDescriptor,get,get"», «"ownKeys,getOwnPropertyDescriptor,get,getOwnPropertyDescriptor,get"») to be true
-test262/test/staging/sm/regress/regress-577648-1.js:21: Test262Error: 1 Expected SameValue(«true», «false») to be true
-test262/test/staging/sm/regress/regress-577648-2.js:14: Test262Error: Expected SameValue(«true», «false») to be true
-test262/test/staging/sm/regress/regress-584355.js:12: Test262Error: Expected SameValue(«"function f () { ff (); }"», «"undefined"») to be true
-test262/test/staging/sm/regress/regress-586482-1.js:19: Test262Error: ok Expected SameValue(«true», «false») to be true
-test262/test/staging/sm/regress/regress-586482-2.js:19: Test262Error: ok Expected SameValue(«true», «false») to be true
-test262/test/staging/sm/regress/regress-586482-3.js:18: Test262Error: ok Expected SameValue(«true», «false») to be true
-test262/test/staging/sm/regress/regress-586482-4.js:14: Test262Error: ok Expected SameValue(«function() { this.f(); }», «undefined») to be true
test262/test/staging/sm/regress/regress-602621.js:14: Test262Error: function sub-statement must override arguments Expected SameValue(«"function"», «"object"») to be true
-test262/test/staging/sm/regress/regress-699682.js:15: Test262Error: Expected SameValue(«false», «true») to be true
test262/test/staging/sm/regress/regress-1383630.js:30: Error: Assertion failed: expected exception TypeError, no exception thrown
test262/test/staging/sm/statements/arrow-function-in-for-statement-head.js:15: Test262Error: expected syntax error, got Error: didn't throw Expected SameValue(«false», «true») to be true
test262/test/staging/sm/statements/regress-642975.js:14: Test262Error: Expected SameValue(«undefined», «"y"») to be true
diff --git a/tests/assert.js b/tests/assert.js
index c8240c8..42369ed 100644
--- a/tests/assert.js
+++ b/tests/assert.js
@@ -3,14 +3,8 @@ export function assert(actual, expected, message) {
expected = true;
if (typeof actual === typeof expected) {
- if (actual === expected) {
- if (actual !== 0 || (1 / actual) === (1 / expected))
- return;
- }
- if (typeof actual === 'number') {
- if (isNaN(actual) && isNaN(expected))
- return;
- }
+ if (Object.is(actual, expected))
+ return;
if (typeof actual === 'object') {
if (actual !== null && expected !== null
&& actual.constructor === expected.constructor
diff --git a/tests/test262.patch b/tests/test262.patch
index b6f4aa5..6956d15 100644
--- a/tests/test262.patch
+++ b/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,13 +83,43 @@ 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 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
+ //-----------------------------------------------------------------------------
+ var BUGNUMBER = 469625;
+ var summary = 'TM: Array prototype and expression closures';
+-var actual = '';
+-var expect = '';
++var actual = null;
+
+
+ //-----------------------------------------------------------------------------
+@@ -24,9 +23,6 @@ test();
+
+ function test()
+ {
+- expect = 'TypeError: [].__proto__ is not a function';
+-
+-
+ Array.prototype.__proto__ = function () { return 3; };
+
+ try
+@@ -35,8 +31,10 @@ function test()
+ }
+ catch(ex)
+ {
+- print(actual = ex + '');
++ print(ex + '');
++ actual = ex;
+ }
+
+- assert.sameValue(expect, actual, summary);
++ assert.sameValue(actual instanceof TypeError, true);
++ assert.sameValue(actual.message.includes("not a function"), true);
+ }
diff --git a/test/staging/sm/misc/new-with-non-constructor.js b/test/staging/sm/misc/new-with-non-constructor.js
index 18c2f0c..f9aa209 100644
--- a/test/staging/sm/misc/new-with-non-constructor.js
diff --git a/tests/test_builtin.js b/tests/test_builtin.js
index ff376ec..a541c19 100644
--- a/tests/test_builtin.js
+++ b/tests/test_builtin.js
@@ -596,7 +596,7 @@ function test_json()
]
]`);
- assert_json_error('\n" @\\x"');
+ assert_json_error('\n" \\@x"');
assert_json_error('\n{ "a": @x }"');
}
diff --git a/tests/test_language.js b/tests/test_language.js
index cda782b..4fa16c8 100644
--- a/tests/test_language.js
+++ b/tests/test_language.js
@@ -2,7 +2,7 @@ function assert(actual, expected, message) {
if (arguments.length == 1)
expected = true;
- if (actual === expected)
+ if (Object.is(actual, expected))
return;
if (actual !== null && expected !== null
diff --git a/tests/test_std.js b/tests/test_std.js
index bb942d6..3debe40 100644
--- a/tests/test_std.js
+++ b/tests/test_std.js
@@ -6,7 +6,7 @@ function assert(actual, expected, message) {
if (arguments.length == 1)
expected = true;
- if (actual === expected)
+ if (Object.is(actual, expected))
return;
if (actual !== null && expected !== null
@@ -129,15 +129,27 @@ function test_popen()
function test_ext_json()
{
var expected, input, obj;
- expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"s":"str"}';
+ expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"b":"abc\\u000bd","s":"str"}';
input = `{ "x":false, /*comments are allowed */
"y":true, // also a comment
z2:null, // unquoted property names
"a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal
- "s":"str",} // trailing comma in objects and arrays
+ "b": "ab\
+c\\vd", // multi-line strings, '\v' escape
+ "s":'str',} // trailing comma in objects and arrays, single quoted string
`;
obj = std.parseExtJSON(input);
assert(JSON.stringify(obj), expected);
+
+ obj = std.parseExtJSON('[Infinity, +Infinity, -Infinity, NaN, +NaN, -NaN, .1, -.2]');
+ assert(obj[0], Infinity);
+ assert(obj[1], Infinity);
+ assert(obj[2], -Infinity);
+ assert(obj[3], NaN);
+ assert(obj[4], NaN);
+ assert(obj[5], NaN);
+ assert(obj[6], 0.1);
+ assert(obj[7], -0.2);
}
function test_os()
diff --git a/unicode_gen.c b/unicode_gen.c
index 1b43538..c793ba1 100644
--- a/unicode_gen.c
+++ b/unicode_gen.c
@@ -2087,10 +2087,9 @@ void build_script_table(FILE *f)
fprintf(f, " UNICODE_SCRIPT_COUNT,\n");
fprintf(f, "} UnicodeScriptEnum;\n\n");
- i = 1;
dump_name_table(f, "unicode_script_name_table",
- unicode_script_name + i, SCRIPT_COUNT - i,
- unicode_script_short_name + i);
+ unicode_script_name, SCRIPT_COUNT,
+ unicode_script_short_name);
dbuf_init(dbuf);
#ifdef DUMP_TABLE_SIZE