diff --git a/Changelog b/Changelog
index 435b39f..0f447db 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,10 @@
+2020-04-12:
+
+- added cross realm support
+- added AggregateError and Promise.any
+- added env, uid and gid options in os.exec()
+- misc bug fixes
+
2020-03-16:
- reworked error handling in std and os libraries: suppressed I/O
diff --git a/TODO b/TODO
index 2f61338..8cfe0be 100644
--- a/TODO
+++ b/TODO
@@ -73,6 +73,6 @@ REPL:
Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
-Test262: 22/70040 errors, 860 excluded, 581 skipped
-test262 commit: 25c9e334d301944537215caba1d7f44319f3e0da
+Test262: 28/70829 errors, 877 excluded, 425 skipped
+Test262 commit: 4a8e49b3ca7f9f74a4cafe6621ff9ba548ccc353
diff --git a/VERSION b/VERSION
index 81b7bb9..69f162a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2020-03-16
+2020-04-12
diff --git a/doc/quickjs.html b/doc/quickjs.html
index b5c9287..550d2a6 100644
--- a/doc/quickjs.html
+++ b/doc/quickjs.html
@@ -72,7 +72,7 @@ ul.no-bullet {list-style: none}
- 3.1 Language support
- Fast interpreter with very low startup time: runs the 69000 tests of the ECMAScript Test Suite2 in about 95 seconds on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds.
-
- Almost complete ES2019 support including modules, asynchronous
+
- Almost complete ES2020 support including modules, asynchronous
generators and full Annex B support (legacy web compatibility). Many
-features from the upcoming ES2020 specification
+features from the upcoming ES2021 specification
3 are also supported.
-
- Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2019 features.
+
- Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2020 features.
- Compile Javascript sources to executables with no external dependency.
@@ -394,18 +394,16 @@ about 100 seconds).
3.1 Language support
-
-3.1.1 ES2019 support
+
+3.1.1 ES2020 support
-The ES2019 specification is almost fully supported including the Annex
+
The ES2020 specification is almost fully supported including the Annex
B (legacy web compatibility) and the Unicode related features.
The following features are not supported yet:
-- Realms (although the C API supports different runtimes and contexts)
-
-
- Tail calls6
+
- Tail calls6
@@ -916,7 +914,21 @@ object containing optional parameters:
stdout
stderr
If present, set the handle in the child for stdin, stdout or stderr.
-
+
+
+env
+Object. If present, set the process environment from the object
+ key-value pairs. Otherwise use the same environment as the current
+ process.
+
+
+uid
+Integer. If present, the process uid with setuid
.
+
+
+gid
+Integer. If present, the process gid with setgid
.
+
@@ -1266,7 +1278,7 @@ Bellard and Charlie Gordon.
-https://www.ecma-international.org/ecma-262/10.0
+https://tc39.es/ecma262/
https://github.com/tc39/test262
diff --git a/doc/quickjs.pdf b/doc/quickjs.pdf
index c0e4f4f..1cba474 100644
Binary files a/doc/quickjs.pdf and b/doc/quickjs.pdf differ
diff --git a/doc/quickjs.texi b/doc/quickjs.texi
index 10152bc..04156af 100644
--- a/doc/quickjs.texi
+++ b/doc/quickjs.texi
@@ -20,8 +20,8 @@
@chapter Introduction
QuickJS is a small and embeddable Javascript engine. It supports the
-upcoming ES2020 specification
-@footnote{@url{https://www.ecma-international.org/ecma-262/10.0}}
+ES2020 specification
+@footnote{@url{https://tc39.es/ecma262/}}
including modules, asynchronous generators, proxies and BigInt.
It supports mathematical extensions such as big decimal float float
@@ -36,12 +36,12 @@ and operator overloading.
@item Fast interpreter with very low startup time: runs the 69000 tests of the ECMAScript Test Suite@footnote{@url{https://github.com/tc39/test262}} in about 95 seconds on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds.
-@item Almost complete ES2019 support including modules, asynchronous
+@item Almost complete ES2020 support including modules, asynchronous
generators and full Annex B support (legacy web compatibility). Many
-features from the upcoming ES2020 specification
+features from the upcoming ES2021 specification
@footnote{@url{https://tc39.github.io/ecma262/}} are also supported.
-@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2019 features.
+@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2020 features.
@item Compile Javascript sources to executables with no external dependency.
@@ -259,17 +259,15 @@ about 100 seconds).
@section Language support
-@subsection ES2019 support
+@subsection ES2020 support
-The ES2019 specification is almost fully supported including the Annex
+The ES2020 specification is almost fully supported including the Annex
B (legacy web compatibility) and the Unicode related features.
The following features are not supported yet:
@itemize
-@item Realms (although the C API supports different runtimes and contexts)
-
@item Tail calls@footnote{We believe the current specification of tails calls is too complicated and presents limited practical interests.}
@end itemize
@@ -704,7 +702,18 @@ object containing optional parameters:
@item stdout
@item stderr
If present, set the handle in the child for stdin, stdout or stderr.
-
+
+ @item env
+ Object. If present, set the process environment from the object
+ key-value pairs. Otherwise use the same environment as the current
+ process.
+
+ @item uid
+ Integer. If present, the process uid with @code{setuid}.
+
+ @item gid
+ Integer. If present, the process gid with @code{setgid}.
+
@end table
@item waitpid(pid, options)
diff --git a/libbf.c b/libbf.c
index 14aff8f..2ef5104 100644
--- a/libbf.c
+++ b/libbf.c
@@ -1701,10 +1701,12 @@ static int __bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
memset(taba, 0, d * sizeof(limb_t));
memcpy(taba + d, a->tab, a->len * sizeof(limb_t));
if (bf_resize(r, n + 1))
+ goto fail1;
+ if (mp_divnorm(s, r->tab, taba, na, b->tab, nb)) {
+ fail1:
+ bf_free(s, taba);
goto fail;
- if (mp_divnorm(s, r->tab, taba, na, b->tab, nb))
- goto fail;
-
+ }
/* see if non zero remainder */
if (mp_scan_nz(taba, nb))
r->tab[0] |= 1;
diff --git a/quickjs-libc.c b/quickjs-libc.c
index 3ff5168..4e6d221 100644
--- a/quickjs-libc.c
+++ b/quickjs-libc.c
@@ -239,6 +239,7 @@ static JSValue js_printf_internal(JSContext *ctx,
case 's':
if (i >= argc)
goto missing;
+ /* XXX: handle strings containing null characters */
string_arg = JS_ToCString(ctx, argv[i++]);
if (!string_arg)
goto fail;
@@ -843,6 +844,7 @@ static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val,
FILE *f;
int i;
const char *str;
+ size_t len;
if (magic == 0) {
f = stdout;
@@ -853,10 +855,10 @@ static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val,
}
for(i = 0; i < argc; i++) {
- str = JS_ToCString(ctx, argv[i]);
+ str = JS_ToCStringLen(ctx, &len, argv[i]);
if (!str)
return JS_EXCEPTION;
- fputs(str, f);
+ fwrite(str, 1, len, f);
JS_FreeCString(ctx, str);
}
return JS_UNDEFINED;
@@ -2325,6 +2327,121 @@ static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
return JS_NewInt32(ctx, ret);
}
+static char **build_envp(JSContext *ctx, JSValueConst obj)
+{
+ uint32_t len, i;
+ JSPropertyEnum *tab;
+ char **envp, *pair;
+ const char *key, *str;
+ JSValue val;
+ size_t key_len, str_len;
+
+ if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj,
+ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0)
+ return NULL;
+ envp = js_mallocz(ctx, sizeof(envp[0]) * ((size_t)len + 1));
+ if (!envp)
+ goto fail;
+ for(i = 0; i < len; i++) {
+ val = JS_GetProperty(ctx, obj, tab[i].atom);
+ if (JS_IsException(val))
+ goto fail;
+ str = JS_ToCString(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!str)
+ goto fail;
+ key = JS_AtomToCString(ctx, tab[i].atom);
+ if (!key) {
+ JS_FreeCString(ctx, str);
+ goto fail;
+ }
+ key_len = strlen(key);
+ str_len = strlen(str);
+ pair = js_malloc(ctx, key_len + str_len + 2);
+ if (!pair) {
+ JS_FreeCString(ctx, key);
+ JS_FreeCString(ctx, str);
+ goto fail;
+ }
+ memcpy(pair, key, key_len);
+ pair[key_len] = '=';
+ memcpy(pair + key_len + 1, str, str_len);
+ pair[key_len + 1 + str_len] = '\0';
+ envp[i] = pair;
+ JS_FreeCString(ctx, key);
+ JS_FreeCString(ctx, str);
+ }
+ done:
+ for(i = 0; i < len; i++)
+ JS_FreeAtom(ctx, tab[i].atom);
+ js_free(ctx, tab);
+ return envp;
+ fail:
+ if (envp) {
+ for(i = 0; i < len; i++)
+ js_free(ctx, envp[i]);
+ js_free(ctx, envp);
+ envp = NULL;
+ }
+ goto done;
+}
+
+/* execvpe is not available on non GNU systems */
+static int my_execvpe(const char *filename, char **argv, char **envp)
+{
+ char *path, *p, *p_next, *p1;
+ char buf[PATH_MAX];
+ size_t filename_len, path_len;
+ BOOL eacces_error;
+
+ filename_len = strlen(filename);
+ if (filename_len == 0) {
+ errno = ENOENT;
+ return -1;
+ }
+ if (strchr(filename, '/'))
+ return execve(filename, argv, envp);
+
+ path = getenv("PATH");
+ if (!path)
+ path = "/bin:/usr/bin";
+ eacces_error = FALSE;
+ p = path;
+ for(p = path; p != NULL; p = p_next) {
+ p1 = strchr(p, ':');
+ if (!p1) {
+ p_next = NULL;
+ path_len = strlen(p);
+ } else {
+ p_next = p1 + 1;
+ path_len = p1 - p;
+ }
+ /* path too long */
+ if ((path_len + 1 + filename_len + 1) > PATH_MAX)
+ continue;
+ memcpy(buf, p, path_len);
+ buf[path_len] = '/';
+ memcpy(buf + path_len + 1, filename, filename_len);
+ buf[path_len + 1 + filename_len] = '\0';
+
+ execve(buf, argv, envp);
+
+ switch(errno) {
+ case EACCES:
+ eacces_error = TRUE;
+ break;
+ case ENOENT:
+ case ENOTDIR:
+ break;
+ default:
+ return -1;
+ }
+ }
+ if (eacces_error)
+ errno = EACCES;
+ return -1;
+}
+
/* exec(args[, options]) -> exitcode */
static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -2332,11 +2449,13 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
JSValueConst options, args = argv[0];
JSValue val, ret_val;
const char **exec_argv, *file = NULL, *str, *cwd = NULL;
+ char **envp = environ;
uint32_t exec_argc, i;
int ret, pid, status;
BOOL block_flag = TRUE, use_path = TRUE;
static const char *std_name[3] = { "stdin", "stdout", "stderr" };
int std_fds[3];
+ uint32_t uid = -1, gid = -1;
val = JS_GetPropertyStr(ctx, args, "length");
if (JS_IsException(val))
@@ -2410,6 +2529,36 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
std_fds[i] = fd;
}
}
+
+ val = JS_GetPropertyStr(ctx, options, "env");
+ if (JS_IsException(val))
+ goto exception;
+ if (!JS_IsUndefined(val)) {
+ envp = build_envp(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!envp)
+ goto exception;
+ }
+
+ val = JS_GetPropertyStr(ctx, options, "uid");
+ if (JS_IsException(val))
+ goto exception;
+ if (!JS_IsUndefined(val)) {
+ ret = JS_ToUint32(ctx, &uid, val);
+ JS_FreeValue(ctx, val);
+ if (ret)
+ goto exception;
+ }
+
+ val = JS_GetPropertyStr(ctx, options, "gid");
+ if (JS_IsException(val))
+ goto exception;
+ if (!JS_IsUndefined(val)) {
+ ret = JS_ToUint32(ctx, &gid, val);
+ JS_FreeValue(ctx, val);
+ if (ret)
+ goto exception;
+ }
}
pid = fork();
@@ -2435,12 +2584,21 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
if (chdir(cwd) < 0)
_exit(127);
}
+ if (uid != -1) {
+ if (setuid(uid) < 0)
+ _exit(127);
+ }
+ if (gid != -1) {
+ if (setgid(gid) < 0)
+ _exit(127);
+ }
+
if (!file)
file = exec_argv[0];
if (use_path)
- ret = execvp(file, (char **)exec_argv);
+ ret = my_execvpe(file, (char **)exec_argv, envp);
else
- ret = execv(file, (char **)exec_argv);
+ ret = execve(file, (char **)exec_argv, envp);
_exit(127);
}
/* parent */
@@ -2467,6 +2625,15 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
for(i = 0; i < exec_argc; i++)
JS_FreeCString(ctx, exec_argv[i]);
js_free(ctx, exec_argv);
+ if (envp != environ) {
+ char **p;
+ p = envp;
+ while (*p != NULL) {
+ js_free(ctx, *p);
+ p++;
+ }
+ js_free(ctx, envp);
+ }
return ret_val;
exception:
ret_val = JS_EXCEPTION;
@@ -2700,14 +2867,15 @@ static JSValue js_print(JSContext *ctx, JSValueConst this_val,
{
int i;
const char *str;
+ size_t len;
for(i = 0; i < argc; i++) {
if (i != 0)
putchar(' ');
- str = JS_ToCString(ctx, argv[i]);
+ str = JS_ToCStringLen(ctx, &len, argv[i]);
if (!str)
return JS_EXCEPTION;
- fputs(str, stdout);
+ fwrite(str, 1, len, stdout);
JS_FreeCString(ctx, str);
}
putchar('\n');
diff --git a/quickjs.c b/quickjs.c
index cabb82b..7da7253 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -187,7 +187,8 @@ typedef enum JSErrorEnum {
JS_TYPE_ERROR,
JS_URI_ERROR,
JS_INTERNAL_ERROR,
-
+ JS_AGGREGATE_ERROR,
+
JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
} JSErrorEnum;
@@ -257,6 +258,15 @@ struct JSRuntime {
#ifdef DUMP_LEAKS
struct list_head string_list; /* list of JSString.link */
#endif
+ /* stack limitation */
+ const uint8_t *stack_top;
+ size_t stack_size; /* in bytes */
+
+ JSValue current_exception;
+ /* true if inside an out of memory error, to avoid recursing */
+ BOOL in_out_of_memory : 8;
+
+ struct JSStackFrame *current_stack_frame;
JSInterruptHandler *interrupt_handler;
void *interrupt_opaque;
@@ -322,6 +332,7 @@ typedef enum {
JS_GC_OBJ_TYPE_SHAPE,
JS_GC_OBJ_TYPE_VAR_REF,
JS_GC_OBJ_TYPE_ASYNC_FUNCTION,
+ JS_GC_OBJ_TYPE_JS_CONTEXT,
} JSGCObjectTypeEnum;
/* header for GC objects. GC objects are C data structures with a
@@ -378,29 +389,30 @@ typedef struct JSBigDecimal {
} JSBigDecimal;
#endif
+typedef enum {
+ JS_AUTOINIT_ID_PROTOTYPE,
+ JS_AUTOINIT_ID_MODULE_NS,
+ JS_AUTOINIT_ID_PROP, /* must be last */
+} JSAutoInitIDEnum;
+
/* must be large enough to have a negligible runtime cost and small
enough to call the interrupt callback often. */
#define JS_INTERRUPT_COUNTER_INIT 10000
struct JSContext {
+ JSGCObjectHeader header; /* must come first */
JSRuntime *rt;
struct list_head link;
- const uint8_t *stack_top;
- size_t stack_size; /* in bytes */
- JSValue current_exception;
- /* true if inside an out of memory error, to avoid recursing */
- BOOL in_out_of_memory : 8;
uint16_t binary_object_count;
int binary_object_size;
JSShape *array_shape; /* initial shape for Array objects */
- JSStackFrame *current_stack_frame;
-
JSValue *class_proto;
JSValue function_proto;
JSValue function_ctor;
+ JSValue array_ctor;
JSValue regexp_ctor;
JSValue promise_ctor;
JSValue native_error_proto[JS_NATIVE_ERROR_COUNT];
@@ -570,6 +582,7 @@ typedef struct JSFunctionBytecode {
uint16_t var_count;
uint16_t defined_arg_count; /* for length function property */
uint16_t stack_size; /* maximum stack size */
+ JSContext *realm; /* function realm */
JSValue *cpool; /* constant pool (self pointer) */
int cpool_count;
int closure_var_count;
@@ -784,8 +797,12 @@ typedef struct JSProperty {
} getset;
JSVarRef *var_ref; /* JS_PROP_VARREF */
struct { /* JS_PROP_AUTOINIT */
- int (*init_func)(JSContext *ctx, JSObject *obj,
- JSAtom prop, void *opaque);
+ /* in order to use only 2 pointers, we compress the realm
+ and the init function pointer */
+ union {
+ JSContext *realm; /* for JS_AUTOINIT_ID_PROP */
+ uintptr_t init_id; /* JS_AUTOINIT_ID_x */
+ } u;
void *opaque;
} init;
} u;
@@ -872,7 +889,8 @@ struct JSObject {
JSVarRef **var_refs;
JSObject *home_object; /* for 'super' access */
} func;
- struct { /* JS_CLASS_C_FUNCTION: 8/12 bytes */
+ struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */
+ JSContext *realm;
JSCFunctionType c_function;
uint8_t length;
uint8_t cproto;
@@ -999,6 +1017,9 @@ static void js_array_mark(JSRuntime *rt, JSValueConst val,
static void js_object_data_finalizer(JSRuntime *rt, JSValue val);
static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func);
+static void js_c_function_finalizer(JSRuntime *rt, JSValue val);
+static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
+ JS_MarkFunc *mark_func);
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val);
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func);
@@ -1131,6 +1152,8 @@ 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_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 void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
@@ -1184,6 +1207,11 @@ static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
JSGCObjectTypeEnum type);
static void remove_gc_object(JSGCObjectHeader *h);
static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s);
+static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
+static int js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
+ void *opaque);
+static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
+ JSAtom atom, void *opaque);
static const JSClassExoticMethods js_arguments_exotic_methods;
static const JSClassExoticMethods js_string_exotic_methods;
@@ -1351,7 +1379,7 @@ typedef struct JSClassShortDef {
static JSClassShortDef const js_std_class_def[] = {
{ JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_OBJECT */
{ JS_ATOM_Array, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARRAY */
- { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */
+ { JS_ATOM_Error, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_ERROR */
{ JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */
{ JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */
{ JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */
@@ -1360,7 +1388,7 @@ static JSClassShortDef const js_std_class_def[] = {
{ JS_ATOM_Arguments, NULL, NULL }, /* JS_CLASS_MAPPED_ARGUMENTS */
{ JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */
{ JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_MODULE_NS */
- { JS_ATOM_Function, NULL, NULL }, /* JS_CLASS_C_FUNCTION */
+ { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */
{ JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */
{ JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */
{ JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */
@@ -1477,6 +1505,32 @@ static void set_dummy_numeric_ops(JSNumericOperations *ops)
#endif /* CONFIG_BIGNUM */
+#if defined(EMSCRIPTEN)
+/* currently no stack limitation */
+static inline uint8_t *js_get_stack_pointer(void)
+{
+ return NULL;
+}
+
+static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
+{
+ return FALSE;
+}
+#else
+/* Note: OS and CPU dependent */
+static inline uint8_t *js_get_stack_pointer(void)
+{
+ return __builtin_frame_address(0);
+}
+
+static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
+{
+ size_t size;
+ size = rt->stack_top - js_get_stack_pointer();
+ return unlikely((size + alloca_size) > rt->stack_size);
+}
+#endif
+
JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
{
JSRuntime *rt;
@@ -1532,6 +1586,11 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call;
if (init_shape_hash(rt))
goto fail;
+
+ rt->stack_top = js_get_stack_pointer();
+ rt->stack_size = JS_DEFAULT_STACK_SIZE;
+ rt->current_exception = JS_NULL;
+
return rt;
fail:
JS_FreeRuntime(rt);
@@ -1798,10 +1857,7 @@ void JS_FreeRuntime(JSRuntime *rt)
struct list_head *el, *el1;
int i;
- list_for_each_safe(el, el1, &rt->context_list) {
- JSContext *ctx = list_entry(el, JSContext, link);
- JS_FreeContext(ctx);
- }
+ JS_FreeValueRT(rt, rt->current_exception);
list_for_each_safe(el, el1, &rt->job_list) {
JSJobEntry *e = list_entry(el, JSJobEntry, link);
@@ -1984,32 +2040,6 @@ void JS_FreeRuntime(JSRuntime *rt)
}
}
-#if defined(EMSCRIPTEN)
-/* currently no stack limitation */
-static inline uint8_t *js_get_stack_pointer(void)
-{
- return NULL;
-}
-
-static inline BOOL js_check_stack_overflow(JSContext *ctx, size_t alloca_size)
-{
- return FALSE;
-}
-#else
-/* Note: OS and CPU dependent */
-static inline uint8_t *js_get_stack_pointer(void)
-{
- return __builtin_frame_address(0);
-}
-
-static inline BOOL js_check_stack_overflow(JSContext *ctx, size_t alloca_size)
-{
- size_t size;
- size = ctx->stack_top - js_get_stack_pointer();
- return unlikely((size + alloca_size) > ctx->stack_size);
-}
-#endif
-
JSContext *JS_NewContextRaw(JSRuntime *rt)
{
JSContext *ctx;
@@ -2018,6 +2048,9 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
ctx = js_mallocz_rt(rt, sizeof(JSContext));
if (!ctx)
return NULL;
+ ctx->header.ref_count = 1;
+ add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT);
+
ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) *
rt->class_count);
if (!ctx->class_proto) {
@@ -2026,9 +2059,6 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
}
ctx->rt = rt;
list_add_tail(&ctx->link, &rt->context_list);
- ctx->stack_top = js_get_stack_pointer();
- ctx->stack_size = JS_DEFAULT_STACK_SIZE;
- ctx->current_exception = JS_NULL;
#ifdef CONFIG_BIGNUM
ctx->bf_ctx = &rt->bf_ctx;
ctx->fp_env.prec = 113;
@@ -2036,6 +2066,7 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
#endif
for(i = 0; i < rt->class_count; i++)
ctx->class_proto[i] = JS_NULL;
+ ctx->array_ctor = JS_NULL;
ctx->regexp_ctor = JS_NULL;
ctx->promise_ctor = JS_NULL;
init_list_head(&ctx->loaded_modules);
@@ -2122,11 +2153,60 @@ static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
}
}
+JSContext *JS_DupContext(JSContext *ctx)
+{
+ ctx->header.ref_count++;
+ return ctx;
+}
+
+/* used by the GC */
+static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
+ JS_MarkFunc *mark_func)
+{
+ 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, ctx->global_obj, mark_func);
+ JS_MarkValue(rt, ctx->global_var_obj, mark_func);
+
+ JS_MarkValue(rt, ctx->throw_type_error, mark_func);
+ JS_MarkValue(rt, ctx->eval_obj, mark_func);
+
+ JS_MarkValue(rt, ctx->array_proto_values, mark_func);
+ for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
+ JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
+ }
+ for(i = 0; i < rt->class_count; i++) {
+ JS_MarkValue(rt, ctx->class_proto[i], mark_func);
+ }
+ JS_MarkValue(rt, ctx->iterator_proto, mark_func);
+ JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);
+ JS_MarkValue(rt, ctx->promise_ctor, mark_func);
+ JS_MarkValue(rt, ctx->array_ctor, mark_func);
+ JS_MarkValue(rt, ctx->regexp_ctor, mark_func);
+ JS_MarkValue(rt, ctx->function_ctor, mark_func);
+ JS_MarkValue(rt, ctx->function_proto, mark_func);
+
+ if (ctx->array_shape)
+ mark_func(rt, &ctx->array_shape->header);
+}
+
void JS_FreeContext(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
int i;
+ if (--ctx->header.ref_count > 0)
+ return;
+ assert(ctx->header.ref_count == 0);
+
#ifdef DUMP_ATOMS
JS_DumpAtoms(ctx->rt);
#endif
@@ -2156,8 +2236,6 @@ void JS_FreeContext(JSContext *ctx)
js_free_modules(ctx, JS_FREE_MODULE_ALL);
- JS_FreeValue(ctx, ctx->current_exception);
-
JS_FreeValue(ctx, ctx->global_obj);
JS_FreeValue(ctx, ctx->global_var_obj);
@@ -2175,6 +2253,7 @@ void JS_FreeContext(JSContext *ctx)
JS_FreeValue(ctx, ctx->iterator_proto);
JS_FreeValue(ctx, ctx->async_iterator_proto);
JS_FreeValue(ctx, ctx->promise_ctor);
+ JS_FreeValue(ctx, ctx->array_ctor);
JS_FreeValue(ctx, ctx->regexp_ctor);
JS_FreeValue(ctx, ctx->function_ctor);
JS_FreeValue(ctx, ctx->function_proto);
@@ -2182,6 +2261,7 @@ void JS_FreeContext(JSContext *ctx)
js_free_shape_null(ctx->rt, ctx->array_shape);
list_del(&ctx->link);
+ remove_gc_object(&ctx->header);
js_free_rt(ctx->rt, ctx);
}
@@ -2190,21 +2270,21 @@ JSRuntime *JS_GetRuntime(JSContext *ctx)
return ctx->rt;
}
-void JS_SetMaxStackSize(JSContext *ctx, size_t stack_size)
+void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size)
{
- ctx->stack_size = stack_size;
+ rt->stack_size = stack_size;
}
static inline BOOL is_strict_mode(JSContext *ctx)
{
- JSStackFrame *sf = ctx->current_stack_frame;
+ JSStackFrame *sf = ctx->rt->current_stack_frame;
return (sf && (sf->js_mode & JS_MODE_STRICT));
}
#ifdef CONFIG_BIGNUM
static inline BOOL is_math_mode(JSContext *ctx)
{
- JSStackFrame *sf = ctx->current_stack_frame;
+ JSStackFrame *sf = ctx->rt->current_stack_frame;
return (sf && (sf->js_mode & JS_MODE_MATH));
}
#endif
@@ -4541,6 +4621,7 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas
p->u.array.u.ptr = NULL;
p->u.array.count = 0;
break;
+ case JS_CLASS_ERROR:
case JS_CLASS_NUMBER:
case JS_CLASS_STRING:
case JS_CLASS_BOOLEAN:
@@ -4775,6 +4856,7 @@ static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
if (JS_IsException(func_obj))
return func_obj;
p = JS_VALUE_GET_OBJ(func_obj);
+ p->u.cfunc.realm = JS_DupContext(ctx);
p->u.cfunc.c_function.generic = func;
p->u.cfunc.length = length;
p->u.cfunc.cproto = cproto;
@@ -4885,6 +4967,21 @@ JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
return func_obj;
}
+static void js_autoinit_free(JSRuntime *rt, JSProperty *pr)
+{
+ if (pr->u.init.u.init_id >= JS_AUTOINIT_ID_PROP) {
+ JS_FreeContext(pr->u.init.u.realm);
+ }
+}
+
+static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr,
+ JS_MarkFunc *mark_func)
+{
+ if (pr->u.init.u.init_id >= JS_AUTOINIT_ID_PROP) {
+ mark_func(rt, &pr->u.init.u.realm->header);
+ }
+}
+
static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
{
if (unlikely(prop_flags & JS_PROP_TMASK)) {
@@ -4896,7 +4993,7 @@ static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
} else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
free_var_ref(rt, pr->u.var_ref);
} else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* nothing to do */
+ js_autoinit_free(rt, pr);
}
} else {
JS_FreeValueRT(rt, pr->u.value);
@@ -5004,6 +5101,23 @@ static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
JS_MarkValue(rt, p->u.object_data, mark_func);
}
+static void js_c_function_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSObject *p = JS_VALUE_GET_OBJ(val);
+
+ if (p->u.cfunc.realm)
+ JS_FreeContext(p->u.cfunc.realm);
+}
+
+static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
+ JS_MarkFunc *mark_func)
+{
+ JSObject *p = JS_VALUE_GET_OBJ(val);
+
+ if (p->u.cfunc.realm)
+ mark_func(rt, &p->u.cfunc.realm->header);
+}
+
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p1, *p = JS_VALUE_GET_OBJ(val);
@@ -5315,7 +5429,7 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
mark_func(rt, &pr->u.var_ref->header);
}
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* nothing to do */
+ js_autoinit_mark(rt, pr, mark_func);
}
} else {
JS_MarkValue(rt, pr->u.value, mark_func);
@@ -5340,6 +5454,8 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
for(i = 0; i < b->cpool_count; i++) {
JS_MarkValue(rt, b->cpool[i], mark_func);
}
+ if (b->realm)
+ mark_func(rt, &b->realm->header);
}
break;
case JS_GC_OBJ_TYPE_VAR_REF:
@@ -5367,45 +5483,17 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
}
}
break;
+ case JS_GC_OBJ_TYPE_JS_CONTEXT:
+ {
+ JSContext *ctx = (JSContext *)gp;
+ JS_MarkContext(rt, ctx, mark_func);
+ }
+ break;
default:
abort();
}
}
-#if 0
-/* not useful until realms are supported */
-static void mark_context(JSRuntime *rt, JSContext *ctx)
-{
- int i;
- struct list_head *el;
-
- list_for_each(el, &ctx->loaded_modules) {
- JSModuleDef *m = list_entry(el, JSModuleDef, link);
- JS_MarkValue(rt, m->module_ns);
- JS_MarkValue(rt, m->func_obj);
- }
-
- JS_MarkValue(rt, ctx->current_exception);
-
- for(i = 0; i < rt->class_count; i++)
- JS_MarkValue(rt, ctx->class_proto[i]);
- JS_MarkValue(rt, ctx->regexp_ctor);
- JS_MarkValue(rt, ctx->function_ctor);
- JS_MarkValue(rt, ctx->function_proto);
- JS_MarkValue(rt, ctx->iterator_proto);
- JS_MarkValue(rt, ctx->async_iterator_proto);
- JS_MarkValue(rt, ctx->array_proto_values);
-
- for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++)
- JS_MarkValue(rt, ctx->native_error_proto[i]);
-
- JS_MarkValue(rt, ctx->throw_type_error);
- JS_MarkValue(rt, ctx->eval_obj);
- JS_MarkValue(rt, ctx->global_obj);
- JS_MarkValue(rt, ctx->global_var_obj);
-}
-#endif
-
static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p)
{
assert(p->ref_count > 0);
@@ -6056,8 +6144,9 @@ JSValue JS_GetGlobalObject(JSContext *ctx)
/* WARNING: obj is freed */
JSValue JS_Throw(JSContext *ctx, JSValue obj)
{
- JS_FreeValue(ctx, ctx->current_exception);
- ctx->current_exception = obj;
+ JSRuntime *rt = ctx->rt;
+ JS_FreeValue(ctx, rt->current_exception);
+ rt->current_exception = obj;
return JS_EXCEPTION;
}
@@ -6065,8 +6154,9 @@ JSValue JS_Throw(JSContext *ctx, JSValue obj)
JSValue JS_GetException(JSContext *ctx)
{
JSValue val;
- val = ctx->current_exception;
- ctx->current_exception = JS_NULL;
+ JSRuntime *rt = ctx->rt;
+ val = rt->current_exception;
+ rt->current_exception = JS_NULL;
return val;
}
@@ -6224,7 +6314,7 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
if (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL)
goto done;
}
- for(sf = ctx->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
+ for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
continue;
@@ -6266,7 +6356,10 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
}
done:
dbuf_putc(&dbuf, '\0');
- str = JS_NewString(ctx, (char *)dbuf.buf);
+ if (dbuf_error(&dbuf))
+ str = JS_NULL;
+ else
+ str = JS_NewString(ctx, (char *)dbuf.buf);
dbuf_free(&dbuf);
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
@@ -6318,12 +6411,13 @@ static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num,
const char *fmt, va_list ap)
{
+ JSRuntime *rt = ctx->rt;
JSStackFrame *sf;
BOOL add_backtrace;
/* the backtrace is added later if called from a bytecode function */
- sf = ctx->current_stack_frame;
- add_backtrace = !ctx->in_out_of_memory &&
+ sf = rt->current_stack_frame;
+ add_backtrace = !rt->in_out_of_memory &&
(!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);
}
@@ -6413,10 +6507,11 @@ JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *c
JSValue JS_ThrowOutOfMemory(JSContext *ctx)
{
- if (!ctx->in_out_of_memory) {
- ctx->in_out_of_memory = TRUE;
+ JSRuntime *rt = ctx->rt;
+ if (!rt->in_out_of_memory) {
+ rt->in_out_of_memory = TRUE;
JS_ThrowInternalError(ctx, "out of memory");
- ctx->in_out_of_memory = FALSE;
+ rt->in_out_of_memory = FALSE;
}
return JS_EXCEPTION;
}
@@ -6674,7 +6769,27 @@ int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj)
static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, JSProperty *pr)
{
- return (*pr->u.init.init_func)(ctx, p, prop, pr->u.init.opaque);
+ int ret;
+ JSContext *realm;
+
+ if (pr->u.init.u.init_id >= JS_AUTOINIT_ID_PROP) {
+ realm = pr->u.init.u.realm;
+ ret = JS_InstantiateFunctionListItem(realm, p, prop, pr->u.init.opaque);
+ if (ret)
+ return ret;
+ } else {
+ switch(pr->u.init.u.init_id) {
+ case JS_AUTOINIT_ID_PROTOTYPE:
+ ret = js_instantiate_prototype(ctx, p, prop, pr->u.init.opaque);
+ break;
+ case JS_AUTOINIT_ID_MODULE_NS:
+ ret = js_module_ns_autoinit(ctx, p, prop, pr->u.init.opaque);
+ break;
+ default:
+ abort();
+ }
+ }
+ return ret;
}
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
@@ -7742,6 +7857,7 @@ static int call_setter(JSContext *ctx, JSObject *setter,
if (JS_IsException(ret))
return -1;
JS_FreeValue(ctx, ret);
+ return TRUE;
} else {
JS_FreeValue(ctx, val);
if ((flags & JS_PROP_THROW) ||
@@ -7749,9 +7865,8 @@ static int call_setter(JSContext *ctx, JSObject *setter,
JS_ThrowTypeError(ctx, "no setter for property");
return -1;
}
- /* XXX: should return FALSE? */
+ return FALSE;
}
- return TRUE;
}
/* set the array length and remove the array elements if necessary. */
@@ -8626,6 +8741,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
/* clear property and update */
if (js_shape_prepare_update(ctx, p, &prs))
return -1;
+ js_autoinit_free(ctx->rt, pr);
prs->flags &= ~JS_PROP_TMASK;
pr->u.value = JS_UNDEFINED;
goto retry;
@@ -8680,6 +8796,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
/* clear property and update */
if (js_shape_prepare_update(ctx, p, &prs))
return -1;
+ js_autoinit_free(ctx->rt, pr);
prs->flags &= ~JS_PROP_TMASK;
pr->u.value = JS_UNDEFINED;
} else {
@@ -8835,8 +8952,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
}
static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, int (*init_func)(JSContext *ctx, JSObject *obj,
- JSAtom prop, void *opaque),
+ JSAtom prop, JSAutoInitIDEnum id,
void *opaque, int flags)
{
JSObject *p;
@@ -8857,8 +8973,11 @@ static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj,
pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT);
if (unlikely(!pr))
return -1;
-
- pr->u.init.init_func = init_func;
+ if (id == JS_AUTOINIT_ID_PROP) {
+ pr->u.init.u.realm = JS_DupContext(ctx);
+ } else {
+ pr->u.init.u.init_id = id;
+ }
pr->u.init.opaque = opaque;
return TRUE;
}
@@ -9334,7 +9453,7 @@ void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag)
void JS_ResetUncatchableError(JSContext *ctx)
{
- JS_SetUncatchableError(ctx, ctx->current_exception, FALSE);
+ JS_SetUncatchableError(ctx, ctx->rt->current_exception, FALSE);
}
void JS_SetOpaque(JSValue obj, void *opaque)
@@ -11276,7 +11395,7 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
printf("[varref %p]", (void *)pr->u.var_ref);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- printf("[autoinit %p %p]", (void *)pr->u.init.init_func,
+ printf("[autoinit %p %p]", (void *)pr->u.init.u.realm,
(void *)pr->u.init.opaque);
} else {
JS_DumpValueShort(rt, pr->u.value);
@@ -11327,6 +11446,9 @@ static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
printf("[async_function]");
break;
+ case JS_GC_OBJ_TYPE_JS_CONTEXT:
+ printf("[js_context]");
+ break;
default:
printf("[unknown %d]", p->gc_obj_type);
break;
@@ -14500,7 +14622,7 @@ static JSValue js_build_mapped_arguments(JSContext *ctx, int argc,
JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
/* callee returns this function in non strict mode */
JS_DefinePropertyValue(ctx, val, JS_ATOM_callee,
- JS_DupValue(ctx, ctx->current_stack_frame->cur_func),
+ JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func),
JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
return val;
fail:
@@ -14822,8 +14944,8 @@ static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
int res;
if (is_exception_pending) {
- ex_obj = ctx->current_exception;
- ctx->current_exception = JS_NULL;
+ ex_obj = ctx->rt->current_exception;
+ ctx->rt->current_exception = JS_NULL;
res = -1;
} else {
ex_obj = JS_UNDEFINED;
@@ -15139,7 +15261,7 @@ static __exception int JS_CopyDataProperties(JSContext *ctx,
/* only valid inside C functions */
static JSValueConst JS_GetActiveFunction(JSContext *ctx)
{
- return ctx->current_stack_frame->cur_func;
+ return ctx->rt->current_stack_frame->cur_func;
}
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
@@ -15231,6 +15353,13 @@ static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, vo
return 0;
}
+static const uint16_t func_kind_to_class_id[] = {
+ [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION,
+ [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION,
+ [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION,
+ [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION,
+};
+
static JSValue js_closure(JSContext *ctx, JSValue bfunc,
JSVarRef **cur_var_refs,
JSStackFrame *sf)
@@ -15238,12 +15367,6 @@ static JSValue js_closure(JSContext *ctx, JSValue bfunc,
JSFunctionBytecode *b;
JSValue func_obj;
JSAtom name_atom;
- static const uint16_t func_kind_to_class_id[] = {
- [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION,
- [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION,
- [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION,
- [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION,
- };
b = JS_VALUE_GET_PTR(bfunc);
func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]);
@@ -15282,7 +15405,7 @@ static JSValue js_closure(JSContext *ctx, JSValue bfunc,
object is created on the fly when first accessed */
JS_SetConstructorBit(ctx, func_obj, TRUE);
JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype,
- js_instantiate_prototype, NULL,
+ JS_AUTOINIT_ID_PROTOTYPE, NULL,
JS_PROP_WRITABLE);
}
return func_obj;
@@ -15435,6 +15558,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
JSValueConst this_obj,
int argc, JSValueConst *argv, int flags)
{
+ JSRuntime *rt = ctx->rt;
JSCFunctionType func;
JSObject *p;
JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
@@ -15448,12 +15572,14 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
arg_count = p->u.cfunc.length;
/* better to always check stack overflow */
- if (js_check_stack_overflow(ctx, sizeof(arg_buf[0]) * arg_count))
+ if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count))
return JS_ThrowStackOverflow(ctx);
- prev_sf = ctx->current_stack_frame;
+ prev_sf = rt->current_stack_frame;
sf->prev_frame = prev_sf;
- ctx->current_stack_frame = sf;
+ rt->current_stack_frame = sf;
+ ctx = p->u.cfunc.realm; /* change the current realm */
+
#ifdef CONFIG_BIGNUM
/* we only propagate the bignum mode as some runtime functions
test it */
@@ -15563,7 +15689,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
abort();
}
- ctx->current_stack_frame = sf->prev_frame;
+ rt->current_stack_frame = sf->prev_frame;
return ret_val;
}
@@ -15579,7 +15705,7 @@ static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
p = JS_VALUE_GET_OBJ(func_obj);
bf = p->u.bound_function;
arg_count = bf->argc + argc;
- if (js_check_stack_overflow(ctx, sizeof(JSValue) * arg_count))
+ if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count))
return JS_ThrowStackOverflow(ctx);
arg_buf = alloca(sizeof(JSValue) * arg_count);
for(i = 0; i < bf->argc; i++) {
@@ -15608,7 +15734,7 @@ static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
/* XXX: should set a specific flag to avoid catching */
JS_ThrowInternalError(ctx, "interrupted");
- JS_SetUncatchableError(ctx, ctx->current_exception, TRUE);
+ JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
return -1;
}
}
@@ -15640,10 +15766,12 @@ typedef enum {
#define FUNC_RET_YIELD_STAR 2
/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
-static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
+static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSValueConst this_obj, JSValueConst new_target,
int argc, JSValue *argv, int flags)
{
+ JSRuntime *rt = caller_ctx->rt;
+ JSContext *ctx;
JSObject *p;
JSFunctionBytecode *b;
JSStackFrame sf_s, *sf = &sf_s;
@@ -15675,7 +15803,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
#define BREAK SWITCH(pc)
#endif
- if (js_poll_interrupts(ctx))
+ if (js_poll_interrupts(caller_ctx))
return JS_EXCEPTION;
if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {
if (flags & JS_CALL_FLAG_GENERATOR) {
@@ -15685,6 +15813,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
sf = &s->frame;
p = JS_VALUE_GET_OBJ(sf->cur_func);
b = p->u.func.function_bytecode;
+ ctx = b->realm;
var_refs = p->u.func.var_refs;
local_buf = arg_buf = sf->arg_buf;
var_buf = sf->var_buf;
@@ -15692,8 +15821,8 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
sp = sf->cur_sp;
sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */
pc = sf->cur_pc;
- sf->prev_frame = ctx->current_stack_frame;
- ctx->current_stack_frame = sf;
+ sf->prev_frame = rt->current_stack_frame;
+ rt->current_stack_frame = sf;
if (s->throw_flag)
goto exception;
else
@@ -15705,12 +15834,12 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
p = JS_VALUE_GET_OBJ(func_obj);
if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
JSClassCall *call_func;
- call_func = ctx->rt->class_array[p->class_id].call;
+ call_func = rt->class_array[p->class_id].call;
if (!call_func) {
not_a_function:
- return JS_ThrowTypeError(ctx, "not a function");
+ return JS_ThrowTypeError(caller_ctx, "not a function");
}
- return call_func(ctx, func_obj, this_obj, argc,
+ return call_func(caller_ctx, func_obj, this_obj, argc,
(JSValueConst *)argv, flags);
}
b = p->u.func.function_bytecode;
@@ -15723,8 +15852,8 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count +
b->stack_size);
- if (js_check_stack_overflow(ctx, alloca_size))
- return JS_ThrowStackOverflow(ctx);
+ if (js_check_stack_overflow(rt, alloca_size))
+ return JS_ThrowStackOverflow(caller_ctx);
sf->js_mode = b->js_mode;
arg_buf = argv;
@@ -15738,7 +15867,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
int n = min_int(argc, b->arg_count);
arg_buf = local_buf;
for(i = 0; i < n; i++)
- arg_buf[i] = JS_DupValue(ctx, argv[i]);
+ arg_buf[i] = JS_DupValue(caller_ctx, argv[i]);
for(; i < b->arg_count; i++)
arg_buf[i] = JS_UNDEFINED;
sf->arg_count = b->arg_count;
@@ -15753,8 +15882,10 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
stack_buf = var_buf + b->var_count;
sp = stack_buf;
pc = b->byte_code_buf;
- sf->prev_frame = ctx->current_stack_frame;
- ctx->current_stack_frame = sf;
+ sf->prev_frame = rt->current_stack_frame;
+ rt->current_stack_frame = sf;
+ ctx = b->realm; /* set the current realm */
+
restart:
for(;;) {
int call_argc;
@@ -16178,7 +16309,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
/* return TRUE if 'this' should be returned */
if (!JS_IsObject(sp[-1])) {
if (!JS_IsUndefined(sp[-1])) {
- JS_ThrowTypeError(ctx, "derived class constructor must return an object or undefined");
+ JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined");
goto exception;
}
sp[0] = JS_TRUE;
@@ -16189,7 +16320,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
BREAK;
CASE(OP_check_ctor):
if (JS_IsUndefined(new_target)) {
- JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'");
+ JS_ThrowTypeError(caller_ctx, "class constructors must be invoked with 'new'");
goto exception;
}
BREAK;
@@ -16673,7 +16804,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom,
JS_PROP_WRITABLE | JS_PROP_VARREF);
if (!pr) {
- free_var_ref(ctx->rt, var_ref);
+ free_var_ref(rt, var_ref);
goto exception;
}
pr->u.var_ref = var_ref;
@@ -16870,6 +17001,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
BREAK;
CASE(OP_iterator_close):
+ /* iter_obj next catch_offset -> */
sp--; /* drop the catch offset to avoid getting caught by exception */
JS_FreeValue(ctx, sp[-1]); /* drop the next method */
sp--;
@@ -16908,24 +17040,28 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
{
JSValue ret, method;
int ret_flag;
- method = JS_GetProperty(ctx, sp[-3], JS_ATOM_return);
+ sp--; /* remove the catch offset */
+ method = JS_GetProperty(ctx, sp[-2], JS_ATOM_return);
if (JS_IsException(method))
goto exception;
if (JS_IsUndefined(method) || JS_IsNull(method)) {
ret = JS_UNDEFINED;
ret_flag = TRUE;
} else {
- ret = JS_CallFree(ctx, method, sp[-3], 0, NULL);
+ ret = JS_CallFree(ctx, method, sp[-2], 0, NULL);
if (JS_IsException(ret))
goto exception;
+ if (!JS_IsObject(ret)) {
+ JS_FreeValue(ctx, ret);
+ JS_ThrowTypeErrorNotAnObject(ctx);
+ goto exception;
+ }
ret_flag = FALSE;
}
- JS_FreeValue(ctx, sp[-3]);
JS_FreeValue(ctx, sp[-2]);
JS_FreeValue(ctx, sp[-1]);
- sp[-3] = ret;
- sp[-2] = JS_NewBool(ctx, ret_flag);
- sp -= 1;
+ sp[-2] = ret;
+ sp[-1] = JS_NewBool(ctx, ret_flag);
}
BREAK;
@@ -16949,6 +17085,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
BOOL ret_flag;
int flags;
flags = *pc++;
+ /* XXX: use another opcode such as OP_throw_var */
if (flags == 2) {
JS_ThrowTypeError(ctx, "iterator does not have a throw method");
goto exception;
@@ -17856,7 +17993,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
#ifdef CONFIG_BIGNUM
CASE(OP_mul_pow10):
- if (ctx->rt->bigfloat_ops.mul_pow10(ctx, sp))
+ if (rt->bigfloat_ops.mul_pow10(ctx, sp))
goto exception;
sp--;
BREAK;
@@ -18101,14 +18238,14 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
}
}
exception:
- if (is_backtrace_needed(ctx, ctx->current_exception)) {
+ if (is_backtrace_needed(ctx, rt->current_exception)) {
/* add the backtrace information now (it is not done
before if the exception happens in a bytecode
operation */
sf->cur_pc = pc;
- build_backtrace(ctx, ctx->current_exception, NULL, 0, 0);
+ build_backtrace(ctx, rt->current_exception, NULL, 0, 0);
}
- if (!JS_IsUncatchableError(ctx, ctx->current_exception)) {
+ if (!JS_IsUncatchableError(ctx, rt->current_exception)) {
while (sp > stack_buf) {
JSValue val = *--sp;
JS_FreeValue(ctx, val);
@@ -18120,8 +18257,8 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
sp--;
JS_IteratorClose(ctx, sp[-1], TRUE);
} else {
- *sp++ = ctx->current_exception;
- ctx->current_exception = JS_NULL;
+ *sp++ = rt->current_exception;
+ rt->current_exception = JS_NULL;
pc = b->byte_code_buf + pos;
goto restart;
}
@@ -18140,14 +18277,14 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
done:
if (unlikely(!list_empty(&sf->var_ref_list))) {
/* variable references reference the stack: must close them */
- close_var_refs(ctx->rt, sf);
+ close_var_refs(rt, sf);
}
/* free the local variables and stack */
for(pval = local_buf; pval < sp; pval++) {
JS_FreeValue(ctx, *pval);
}
}
- ctx->current_stack_frame = sf->prev_frame;
+ rt->current_stack_frame = sf->prev_frame;
return ret_val;
}
@@ -18167,24 +18304,62 @@ static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_o
return res;
}
-static JSValue js_get_prototype_from_ctor(JSContext *ctx, JSValueConst ctor,
- JSValueConst def_proto)
+/* warning: the refcount of the context is not incremented. Return
+ NULL in case of exception (case of revoked proxy only) */
+static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)
{
- JSValue proto;
- proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
- if (JS_IsException(proto))
- return proto;
- if (!JS_IsObject(proto)) {
- JS_FreeValue(ctx, proto);
- proto = JS_DupValue(ctx, def_proto);
+ JSObject *p;
+ JSContext *realm;
+
+ if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
+ return ctx;
+ p = JS_VALUE_GET_OBJ(func_obj);
+ switch(p->class_id) {
+ case JS_CLASS_C_FUNCTION:
+ realm = p->u.cfunc.realm;
+ break;
+ case JS_CLASS_BYTECODE_FUNCTION:
+ case JS_CLASS_GENERATOR_FUNCTION:
+ case JS_CLASS_ASYNC_FUNCTION:
+ case JS_CLASS_ASYNC_GENERATOR_FUNCTION:
+ {
+ JSFunctionBytecode *b;
+ b = p->u.func.function_bytecode;
+ realm = b->realm;
+ }
+ break;
+ case JS_CLASS_PROXY:
+ {
+ JSProxyData *s = p->u.opaque;
+ if (!s)
+ return ctx;
+ if (s->is_revoked) {
+ JS_ThrowTypeErrorRevokedProxy(ctx);
+ return NULL;
+ } else {
+ realm = JS_GetFunctionRealm(ctx, s->target);
+ }
+ }
+ break;
+ case JS_CLASS_BOUND_FUNCTION:
+ {
+ JSBoundFunction *bf = p->u.bound_function;
+ realm = JS_GetFunctionRealm(ctx, bf->func_obj);
+ }
+ break;
+ default:
+ realm = ctx;
+ break;
}
- return proto;
+ return realm;
}
static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
int class_id)
{
JSValue proto, obj;
+ JSContext *realm;
+
if (JS_IsUndefined(ctor)) {
proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
} else {
@@ -18193,14 +18368,10 @@ static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
return proto;
if (!JS_IsObject(proto)) {
JS_FreeValue(ctx, proto);
- /* check if revoked proxy */
- {
- JSProxyData *s = JS_GetOpaque(ctor, JS_CLASS_PROXY);
- if (s && s->is_revoked)
- return JS_ThrowTypeErrorRevokedProxy(ctx);
- }
- /* XXX: should use the ctor realm instead of 'ctx' */
- proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
+ realm = JS_GetFunctionRealm(ctx, ctor);
+ if (!realm)
+ return JS_EXCEPTION;
+ proto = JS_DupValue(ctx, realm->class_proto[class_id]);
}
}
obj = JS_NewObjectProtoClass(ctx, proto, class_id);
@@ -19709,7 +19880,7 @@ int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const
backtrace_flags = 0;
if (s->cur_func && s->cur_func->backtrace_barrier)
backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
- build_backtrace(ctx, ctx->current_exception, s->filename, s->line_num,
+ build_backtrace(ctx, ctx->rt->current_exception, s->filename, s->line_num,
backtrace_flags);
return -1;
}
@@ -20039,14 +20210,90 @@ static __exception int js_parse_regexp(JSParseState *s)
return -1;
}
+static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
+ char *static_buf)
+{
+ char *buf, *new_buf;
+ size_t size, new_size;
+
+ buf = *pbuf;
+ size = *psize;
+ if (size >= (SIZE_MAX / 3) * 2)
+ new_size = SIZE_MAX;
+ else
+ new_size = size + (size >> 1);
+ if (buf == static_buf) {
+ new_buf = js_malloc(ctx, new_size);
+ if (!new_buf)
+ return -1;
+ memcpy(new_buf, buf, size);
+ } else {
+ new_buf = js_realloc(ctx, buf, new_size);
+ if (!new_buf)
+ return -1;
+ }
+ *pbuf = new_buf;
+ *psize = new_size;
+ return 0;
+}
+
+/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
+static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
+ BOOL *pident_has_escape, int c, BOOL is_private)
+{
+ const uint8_t *p, *p1;
+ char ident_buf[128], *buf;
+ size_t ident_size, ident_pos;
+ JSAtom atom;
+
+ p = *pp;
+ buf = ident_buf;
+ ident_size = sizeof(ident_buf);
+ ident_pos = 0;
+ if (is_private)
+ buf[ident_pos++] = '#';
+ for(;;) {
+ p1 = p;
+
+ if (c < 128) {
+ buf[ident_pos++] = c;
+ } else {
+ ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c);
+ }
+ c = *p1++;
+ if (c == '\\' && *p1 == 'u') {
+ c = lre_parse_escape(&p1, TRUE);
+ *pident_has_escape = TRUE;
+ } else if (c >= 128) {
+ c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
+ }
+ if (!lre_js_is_ident_next(c))
+ break;
+ p = p1;
+ if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
+ if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
+ atom = JS_ATOM_NULL;
+ goto done;
+ }
+ }
+ }
+ atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
+ done:
+ if (unlikely(buf != ident_buf))
+ js_free(s->ctx, buf);
+ *pp = p;
+ return atom;
+}
+
+
static __exception int next_token(JSParseState *s)
{
const uint8_t *p;
int c;
- char buf[4096], *q;
BOOL ident_has_escape;
-
- if (js_check_stack_overflow(s->ctx, 0)) {
+ JSAtom atom;
+
+ if (js_check_stack_overflow(s->ctx->rt, 0)) {
return js_parse_error(s, "stack overflow");
}
@@ -20128,6 +20375,8 @@ static __exception int next_token(JSParseState *s)
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
if (c == CP_LS || c == CP_PS) {
s->got_lf = TRUE; /* considered as LF for ASI */
+ } else if (c == -1) {
+ p++; /* skip invalid UTF-8 */
}
} else {
p++;
@@ -20146,8 +20395,11 @@ static __exception int next_token(JSParseState *s)
if (*p >= 0x80) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
/* LS or PS are considered as line terminator */
- if (c == CP_LS || c == CP_PS)
+ if (c == CP_LS || c == CP_PS) {
break;
+ } else if (c == -1) {
+ p++; /* skip invalid UTF-8 */
+ }
} else {
p++;
}
@@ -20183,33 +20435,10 @@ static __exception int next_token(JSParseState *s)
p++;
ident_has_escape = FALSE;
has_ident:
- q = buf;
- for(;;) {
- const uint8_t *p1 = p;
-
- if (c < 128) {
- *q++ = c;
- } else {
- q += unicode_to_utf8((uint8_t*)q, c);
- }
- c = *p1++;
- if (c == '\\' && *p1 == 'u') {
- c = lre_parse_escape(&p1, TRUE);
- ident_has_escape = TRUE;
- } else if (c >= 128) {
- c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
- }
- /* XXX: check if c >= 0 and c <= 0x10FFFF */
- if (!lre_js_is_ident_next(c))
- break;
- p = p1;
- if ((q - buf) >= sizeof(buf) - UTF8_CHAR_LEN_MAX) {
- js_parse_error(s, "identifier too long");
- goto fail;
- }
- }
- *q = '\0';
- s->token.u.ident.atom = JS_NewAtomLen(s->ctx, buf, q - buf);
+ atom = parse_ident(s, &p, &ident_has_escape, c, FALSE);
+ if (atom == JS_ATOM_NULL)
+ goto fail;
+ s->token.u.ident.atom = atom;
s->token.u.ident.has_escape = ident_has_escape;
s->token.u.ident.is_reserved = FALSE;
if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
@@ -20243,8 +20472,6 @@ static __exception int next_token(JSParseState *s)
{
const uint8_t *p1;
p++;
- q = buf;
- *q++ = '#';
p1 = p;
c = *p1++;
if (c == '\\' && *p1 == 'u') {
@@ -20257,31 +20484,11 @@ static __exception int next_token(JSParseState *s)
goto fail;
}
p = p1;
- for(;;) {
- if (c < 128) {
- *q++ = c;
- } else {
- q += unicode_to_utf8((uint8_t*)q, c);
- }
- p1 = p;
- c = *p1++;
- if (c == '\\' && *p1 == 'u') {
- c = lre_parse_escape(&p1, TRUE);
- ident_has_escape = TRUE;
- } else if (c >= 128) {
- c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
- }
- /* XXX: check if c >= 0 and c <= 0x10FFFF */
- if (!lre_js_is_ident_next(c))
- break;
- p = p1;
- if ((q - buf) >= sizeof(buf) - UTF8_CHAR_LEN_MAX) {
- js_parse_error(s, "private name too long");
- goto fail;
- }
- }
- *q = '\0';
- s->token.u.ident.atom = JS_NewAtomLen(s->ctx, buf, q - buf);
+ ident_has_escape = FALSE; /* not used */
+ atom = parse_ident(s, &p, &ident_has_escape, c, TRUE);
+ if (atom == JS_ATOM_NULL)
+ goto fail;
+ s->token.u.ident.atom = atom;
s->token.val = TOK_PRIVATE_NAME;
}
break;
@@ -22175,16 +22382,25 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
continue;
}
is_static = (s->token.val == TOK_STATIC);
+ prop_type = -1;
if (is_static) {
if (next_token(s))
goto fail;
+ /* allow "static" field name */
+ if (s->token.val == ';' || s->token.val == '=') {
+ is_static = FALSE;
+ name = JS_DupAtom(ctx, JS_ATOM_static);
+ prop_type = PROP_TYPE_IDENT;
+ }
}
if (is_static)
emit_op(s, OP_swap);
start_ptr = s->token.ptr;
- prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE);
- if (prop_type < 0)
- goto fail;
+ if (prop_type < 0) {
+ prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE);
+ if (prop_type < 0)
+ goto fail;
+ }
is_private = prop_type & PROP_TYPE_PRIVATE;
prop_type &= ~PROP_TYPE_PRIVATE;
@@ -22980,7 +23196,7 @@ duplicate:
return js_parse_error(s, "duplicate parameter names not allowed in this context");
}
-static JSAtom js_parse_destructing_var(JSParseState *s, int tok, int is_arg)
+static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)
{
JSAtom name;
@@ -23002,7 +23218,7 @@ fail:
return JS_ATOM_NULL;
}
-static int js_parse_destructing_element(JSParseState *s, int tok, int is_arg,
+static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
int hasval, int has_ellipsis,
BOOL allow_initializer)
{
@@ -23055,7 +23271,7 @@ static int js_parse_destructing_element(JSParseState *s, int tok, int is_arg,
if (next_token(s))
return -1;
if (tok) {
- var_name = js_parse_destructing_var(s, tok, is_arg);
+ var_name = js_parse_destructuring_var(s, tok, is_arg);
if (var_name == JS_ATOM_NULL)
return -1;
opcode = OP_scope_get_var;
@@ -23119,7 +23335,7 @@ static int js_parse_destructing_element(JSParseState *s, int tok, int is_arg,
emit_op(s, OP_get_field2);
emit_u32(s, prop_name);
}
- if (js_parse_destructing_element(s, tok, is_arg, TRUE, -1, TRUE))
+ if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE))
return -1;
if (s->token.val == '}')
break;
@@ -23152,7 +23368,7 @@ static int js_parse_destructing_element(JSParseState *s, int tok, int is_arg,
emit_op(s, OP_dup);
}
if (tok) {
- var_name = js_parse_destructing_var(s, tok, is_arg);
+ var_name = js_parse_destructuring_var(s, tok, is_arg);
if (var_name == JS_ATOM_NULL)
goto prop_error;
} else {
@@ -23316,13 +23532,13 @@ static int js_parse_destructing_element(JSParseState *s, int tok, int is_arg,
emit_u8(s, 0);
emit_op(s, OP_drop);
}
- if (js_parse_destructing_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
return -1;
} else {
var_name = JS_ATOM_NULL;
enum_depth = 0;
if (tok) {
- var_name = js_parse_destructing_var(s, tok, is_arg);
+ var_name = js_parse_destructuring_var(s, tok, is_arg);
if (var_name == JS_ATOM_NULL)
goto var_error;
if (js_define_var(s, var_name, tok))
@@ -23393,7 +23609,13 @@ static int js_parse_destructing_element(JSParseState *s, int tok, int is_arg,
emit_goto(s, OP_goto, label_assign);
emit_label(s, label_done);
} else {
- assert(hasval);
+ /* normally hasval is true except if
+ js_parse_skip_parens_token() was wrong in the parsing */
+ // assert(hasval);
+ if (!hasval) {
+ js_parse_error(s, "too complicated destructuring expression");
+ return -1;
+ }
/* remove test and decrement label ref count */
memset(s->cur_func->byte_code.buf + start_addr, OP_nop,
assign_addr - start_addr);
@@ -23515,7 +23737,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
backtrace_flags = 0;
if (s->cur_func && s->cur_func->backtrace_barrier)
backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
- build_backtrace(s->ctx, s->ctx->current_exception,
+ build_backtrace(s->ctx, s->ctx->rt->current_exception,
s->filename, s->token.line_num,
backtrace_flags);
return -1;
@@ -23633,7 +23855,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
{
int skip_bits;
if (js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
- if (js_parse_destructing_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
return -1;
} else {
if (s->token.val == '{') {
@@ -24851,6 +25073,8 @@ static void emit_return(JSParseState *s, BOOL hasval)
label_return = -1;
}
+ /* XXX: if this is not initialized, should throw the
+ ReferenceError in the caller realm */
emit_op(s, OP_scope_get_var);
emit_atom(s, JS_ATOM_this);
emit_u16(s, 0);
@@ -24977,7 +25201,7 @@ static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok,
if ((s->token.val == '[' || s->token.val == '{')
&& js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
emit_op(s, OP_undefined);
- if (js_parse_destructing_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
return -1;
} else {
return js_parse_error(s, "variable name expected");
@@ -25106,7 +25330,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
if (s->token.val == '[' || s->token.val == '{') {
- if (js_parse_destructing_element(s, tok, 0, TRUE, -1, FALSE))
+ if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE))
return -1;
has_destructuring = TRUE;
} else {
@@ -25132,7 +25356,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
int skip_bits;
if ((s->token.val == '[' || s->token.val == '{')
&& ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {
- if (js_parse_destructing_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
return -1;
} else {
int lvalue_label, depth;
@@ -25815,7 +26039,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
if (s->token.val == '[' || s->token.val == '{') {
/* XXX: TOK_LET is not completely correct */
- if (js_parse_destructing_element(s, TOK_LET, 0, TRUE, -1, TRUE))
+ if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE))
goto fail;
} else {
js_parse_error(s, "identifier expected");
@@ -26038,6 +26262,25 @@ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
return m;
}
+static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
+ JS_MarkFunc *mark_func)
+{
+ int i;
+
+ for(i = 0; i < m->export_entries_count; i++) {
+ JSExportEntry *me = &m->export_entries[i];
+ if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
+ me->u.local.var_ref) {
+ mark_func(rt, &me->u.local.var_ref->header);
+ }
+ }
+
+ JS_MarkValue(rt, m->module_ns, mark_func);
+ JS_MarkValue(rt, m->func_obj, mark_func);
+ JS_MarkValue(rt, m->eval_exception, mark_func);
+ JS_MarkValue(rt, m->meta_obj, mark_func);
+}
+
static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
{
int i;
@@ -26769,7 +27012,7 @@ static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
/* the exported namespace must be created on demand */
if (JS_DefineAutoInitProperty(ctx, obj,
en->export_name,
- js_module_ns_autoinit,
+ JS_AUTOINIT_ID_MODULE_NS,
en->u.module, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
goto fail;
break;
@@ -27075,7 +27318,7 @@ static JSAtom js_get_script_or_module_name(JSContext *ctx)
/* XXX: currently we just use the filename of the englobing
function. It does not work for eval(). Need to add a
ScriptOrModule info in JSFunctionBytecode */
- sf = ctx->current_stack_frame;
+ sf = ctx->rt->current_stack_frame;
assert(sf != NULL);
assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);
p = JS_VALUE_GET_OBJ(sf->cur_func);
@@ -27125,22 +27368,23 @@ static JSValue js_import_meta(JSContext *ctx)
return JS_GetImportMeta(ctx, m);
}
-static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
+static JSValue js_dynamic_import_job(JSContext *ctx,
+ int argc, JSValueConst *argv)
{
+ JSValueConst *resolving_funcs = argv;
+ JSValueConst basename_val = argv[2];
+ JSValueConst specifier = argv[3];
JSModuleDef *m;
- JSAtom basename, filename;
- JSValue promise, resolving_funcs[2];
+ JSAtom basename = JS_ATOM_NULL, filename;
JSValue specifierString, ret, func_obj, err, ns;
-
- promise = JS_NewPromiseCapability(ctx, resolving_funcs);
- if (JS_IsException(promise))
- return promise;
-
- basename = js_get_script_or_module_name(ctx);
- if (basename == JS_ATOM_NULL) {
+
+ if (!JS_IsString(basename_val)) {
JS_ThrowTypeError(ctx, "no function filename for import()");
goto exception;
}
+ basename = JS_ValueToAtom(ctx, basename_val);
+ if (basename == JS_ATOM_NULL)
+ goto exception;
specifierString = JS_ToString(ctx, specifier);
if (JS_IsException(specifierString))
@@ -27177,16 +27421,47 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
1, (JSValueConst *)&ns);
JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
JS_FreeValue(ctx, ns);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- return promise;
-
+ JS_FreeAtom(ctx, basename);
+ return JS_UNDEFINED;
exception:
+
err = JS_GetException(ctx);
ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
1, (JSValueConst *)&err);
JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
JS_FreeValue(ctx, err);
+ JS_FreeAtom(ctx, basename);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
+{
+ JSAtom basename;
+ JSValue promise, resolving_funcs[2], basename_val;
+ JSValueConst args[4];
+
+ basename = js_get_script_or_module_name(ctx);
+ if (basename == JS_ATOM_NULL)
+ basename_val = JS_NULL;
+ else
+ basename_val = JS_AtomToValue(ctx, basename);
+ if (JS_IsException(basename_val))
+ return basename_val;
+
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
+ if (JS_IsException(promise)) {
+ JS_FreeValue(ctx, basename_val);
+ return promise;
+ }
+
+ args[0] = resolving_funcs[0];
+ args[1] = resolving_funcs[1];
+ args[2] = basename_val;
+ args[3] = specifier;
+
+ JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args);
+
+ JS_FreeValue(ctx, basename_val);
JS_FreeValue(ctx, resolving_funcs[0]);
JS_FreeValue(ctx, resolving_funcs[1]);
return promise;
@@ -27241,7 +27516,7 @@ static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
if (JS_IsException(ret_val)) {
/* save the thrown exception value */
m->eval_has_exception = TRUE;
- m->eval_exception = JS_DupValue(ctx, ctx->current_exception);
+ m->eval_exception = JS_DupValue(ctx, ctx->rt->current_exception);
}
m->eval_mark = FALSE;
m->evaluated = TRUE;
@@ -27521,6 +27796,10 @@ static __exception int js_parse_import(JSParseState *s)
return js_parse_error(s, "expecting 'as'");
if (next_token(s))
return -1;
+ if (!token_is_ident(s->token.val)) {
+ js_parse_error(s, "identifier expected");
+ return -1;
+ }
local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
import_name = JS_ATOM__star_;
if (next_token(s))
@@ -31469,6 +31748,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
b->super_allowed = fd->super_allowed;
b->arguments_allowed = fd->arguments_allowed;
b->backtrace_barrier = fd->backtrace_barrier;
+ b->realm = JS_DupContext(ctx);
add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
@@ -31515,6 +31795,8 @@ static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
JSClosureVar *cv = &b->closure_var[i];
JS_FreeAtomRT(rt, cv->var_name);
}
+ if (b->realm)
+ JS_FreeContext(b->realm);
JS_FreeAtomRT(rt, b->func_name);
if (b->has_debug) {
@@ -31910,7 +32192,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
emit_op(s, OP_get_arg);
emit_u16(s, idx);
}
- if (js_parse_destructing_element(s, TOK_VAR, 1, TRUE, -1, TRUE))
+ if (js_parse_destructuring_element(s, TOK_VAR, 1, TRUE, -1, TRUE))
goto fail;
} else if (s->token.val == TOK_IDENT) {
if (s->token.u.ident.is_reserved) {
@@ -32309,8 +32591,11 @@ static void skip_shebang(JSParseState *s)
break;
} else if (*p >= 0x80) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
- if (c == CP_LS || c == CP_PS)
+ if (c == CP_LS || c == CP_PS) {
break;
+ } else if (c == -1) {
+ p++; /* skip invalid UTF-8 */
+ }
} else {
p++;
}
@@ -32340,7 +32625,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
m = NULL;
if (eval_type == JS_EVAL_TYPE_DIRECT) {
JSObject *p;
- sf = ctx->current_stack_frame;
+ sf = ctx->rt->current_stack_frame;
assert(sf != NULL);
assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);
p = JS_VALUE_GET_OBJ(sf->cur_func);
@@ -33907,6 +34192,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s)
bc_read_trace(s, "}\n");
}
bc_read_trace(s, "}\n");
+ b->realm = JS_DupContext(ctx);
}
break;
case BC_TAG_MODULE:
@@ -34095,8 +34381,9 @@ static JSValue JS_ReadObjectRec(BCReaderState *s)
fail:
if (m) {
js_free_module_def(ctx, m);
+ } else {
+ JS_FreeValue(ctx, obj);
}
- JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
@@ -34336,7 +34623,7 @@ void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
case JS_DEF_OBJECT:
prop_flags = JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE | (e->prop_flags & JS_PROP_ENUMERABLE);
JS_DefineAutoInitProperty(ctx, obj, atom,
- JS_InstantiateFunctionListItem,
+ JS_AUTOINIT_ID_PROP,
(void *)e, prop_flags);
break;
case JS_DEF_PROP_INT32:
@@ -35816,15 +36103,21 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
goto fail1;
if (!JS_IsUndefined(new_target)) {
/* set the prototype */
- proto = js_get_prototype_from_ctor(ctx, new_target, JS_UNDEFINED);
+ proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
if (JS_IsException(proto))
goto fail1;
- if (!JS_IsUndefined(proto)) {
- ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE);
+ if (!JS_IsObject(proto)) {
+ JSContext *realm;
JS_FreeValue(ctx, proto);
- if (ret < 0)
+ realm = JS_GetFunctionRealm(ctx, new_target);
+ if (!realm)
goto fail1;
+ proto = JS_DupValue(ctx, realm->class_proto[func_kind_to_class_id[func_kind]]);
}
+ ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE);
+ JS_FreeValue(ctx, proto);
+ if (ret < 0)
+ goto fail1;
}
return obj;
@@ -36073,29 +36366,90 @@ static const JSCFunctionListEntry js_function_proto_funcs[] = {
/* Error class */
+static JSValue iterator_to_array(JSContext *ctx, JSValueConst items)
+{
+ JSValue iter, next_method = JS_UNDEFINED;
+ JSValue v, r = JS_UNDEFINED;
+ int64_t k;
+ BOOL done;
+
+ iter = JS_GetIterator(ctx, items, FALSE);
+ if (JS_IsException(iter))
+ goto exception;
+ next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
+ if (JS_IsException(next_method))
+ goto exception;
+ r = JS_NewArray(ctx);
+ if (JS_IsException(r))
+ goto exception;
+ for (k = 0;; k++) {
+ v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
+ if (JS_IsException(v))
+ goto exception_close;
+ if (done)
+ break;
+ if (JS_DefinePropertyValueInt64(ctx, r, k, v,
+ JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+ goto exception_close;
+ }
+ done:
+ JS_FreeValue(ctx, next_method);
+ JS_FreeValue(ctx, iter);
+ return r;
+ exception_close:
+ JS_IteratorClose(ctx, iter, TRUE);
+ exception:
+ JS_FreeValue(ctx, r);
+ r = JS_EXCEPTION;
+ goto done;
+}
+
static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
int argc, JSValueConst *argv, int magic)
{
JSValue obj, msg, proto;
- JSValueConst proto1;
+ JSValueConst message;
if (JS_IsUndefined(new_target))
new_target = JS_GetActiveFunction(ctx);
- if (magic < 0) {
- proto1 = ctx->class_proto[JS_CLASS_ERROR];
- } else {
- proto1 = ctx->native_error_proto[magic];
- }
- proto = js_get_prototype_from_ctor(ctx, new_target, proto1);
+ proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
if (JS_IsException(proto))
return proto;
+ if (!JS_IsObject(proto)) {
+ JSContext *realm;
+ JSValueConst proto1;
+
+ JS_FreeValue(ctx, proto);
+ realm = JS_GetFunctionRealm(ctx, new_target);
+ if (!realm)
+ return JS_EXCEPTION;
+ if (magic < 0) {
+ proto1 = realm->class_proto[JS_CLASS_ERROR];
+ } else {
+ proto1 = realm->native_error_proto[magic];
+ }
+ proto = JS_DupValue(ctx, proto1);
+ }
obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR);
JS_FreeValue(ctx, proto);
if (JS_IsException(obj))
return obj;
- if (!JS_IsUndefined(argv[0])) {
- msg = JS_ToString(ctx, argv[0]);
+ if (magic == JS_AGGREGATE_ERROR) {
+ JSObject *p;
+ JSValue error_list = iterator_to_array(ctx, argv[0]);
+ if (JS_IsException(error_list))
+ goto exception;
+ p = JS_VALUE_GET_OBJ(obj);
+ p->u.object_data = error_list;
+ message = argv[1];
+ } else {
+ message = argv[0];
+ }
+
+ if (!JS_IsUndefined(message)) {
+ msg = JS_ToString(ctx, message);
if (unlikely(JS_IsException(msg))) {
+ exception:
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
@@ -36142,6 +36496,58 @@ static const JSCFunctionListEntry js_error_proto_funcs[] = {
JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
};
+/* AggregateError */
+
+/* used by C code. 'errors' must be a fast array. */
+static JSValue js_aggregate_error_constructor(JSContext *ctx,
+ JSValueConst errors)
+{
+ JSValue obj;
+ JSObject *p;
+
+ obj = JS_NewObjectProtoClass(ctx,
+ ctx->native_error_proto[JS_AGGREGATE_ERROR],
+ JS_CLASS_ERROR);
+ if (JS_IsException(obj))
+ return obj;
+ p = JS_VALUE_GET_OBJ(obj);
+ p->u.object_data = JS_DupValue(ctx, errors);
+ return obj;
+}
+
+static JSValue js_aggregate_error_errors(JSContext *ctx, JSValueConst this_val)
+{
+ JSObject *p;
+ JSValue r, *arr;
+ uint32_t len, i;
+
+ if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
+ goto invalid_type;
+ p = JS_VALUE_GET_OBJ(this_val);
+ if (p->class_id != JS_CLASS_ERROR)
+ goto invalid_type;
+ if (!js_get_fast_array(ctx, p->u.object_data, &arr, &len)) {
+ invalid_type:
+ return JS_ThrowTypeError(ctx, "not an AggregateError");
+ }
+ r = JS_NewArray(ctx);
+ if (JS_IsException(r))
+ goto exception;
+ for(i = 0; i < len; i++) {
+ if (JS_DefinePropertyValueInt64(ctx, r, i, JS_DupValue(ctx, arr[i]),
+ JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+ goto exception;
+ }
+ return r;
+ exception:
+ JS_FreeValue(ctx, r);
+ return JS_EXCEPTION;
+}
+
+static const JSCFunctionListEntry js_aggregate_error_proto_funcs[] = {
+ JS_CGETSET_DEF("errors", js_aggregate_error_errors, NULL),
+};
+
/* Array */
static int JS_CopySubArray(JSContext *ctx,
@@ -36367,22 +36773,47 @@ static JSValue js_get_this(JSContext *ctx,
static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj,
JSValueConst len_val)
{
- JSValue ctor, ret;
+ JSValue ctor, ret, species;
int res;
-
+ JSContext *realm;
+
res = JS_IsArray(ctx, obj);
if (res < 0)
return JS_EXCEPTION;
if (!res)
return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
- ctor = JS_SpeciesConstructor(ctx, obj, JS_UNDEFINED);
+ ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
if (JS_IsException(ctor))
- return JS_EXCEPTION;
- if (JS_IsUndefined(ctor))
+ return ctor;
+ if (JS_IsConstructor(ctx, ctor)) {
+ /* legacy web compatibility */
+ realm = JS_GetFunctionRealm(ctx, ctor);
+ if (!realm) {
+ JS_FreeValue(ctx, ctor);
+ return JS_EXCEPTION;
+ }
+ if (realm != ctx &&
+ js_same_value(ctx, ctor, realm->array_ctor)) {
+ JS_FreeValue(ctx, ctor);
+ ctor = JS_UNDEFINED;
+ }
+ }
+ if (JS_IsObject(ctor)) {
+ species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
+ JS_FreeValue(ctx, ctor);
+ if (JS_IsException(species))
+ return species;
+ ctor = species;
+ if (JS_IsNull(ctor))
+ ctor = JS_UNDEFINED;
+ }
+ if (JS_IsUndefined(ctor)) {
return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
- ret = JS_CallConstructor(ctx, ctor, 1, &len_val);
- JS_FreeValue(ctx, ctor);
- return ret;
+ } else {
+ ret = JS_CallConstructor(ctx, ctor, 1, &len_val);
+ JS_FreeValue(ctx, ctor);
+ return ret;
+ }
}
static const JSCFunctionListEntry js_array_funcs[] = {
@@ -36435,7 +36866,7 @@ static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val,
if (res) {
if (js_get_length64(ctx, &len, e))
goto exception;
- if (n + len >= MAX_SAFE_INTEGER) {
+ if (n + len > MAX_SAFE_INTEGER) {
JS_ThrowTypeError(ctx, "Array loo long");
goto exception;
}
@@ -38221,14 +38652,31 @@ static int js_string_define_own_property(JSContext *ctx,
JSValueConst setter, int flags)
{
uint32_t idx;
-
+ JSObject *p;
+ JSString *p1, *p2;
+
if (__JS_AtomIsTaggedInt(prop)) {
idx = __JS_AtomToUInt32(prop);
- if (idx >= js_string_obj_get_length(ctx, this_obj))
+ p = JS_VALUE_GET_OBJ(this_obj);
+ if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)
+ goto def;
+ p1 = JS_VALUE_GET_STRING(p->u.object_data);
+ if (idx >= p1->len)
goto def;
if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags))
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
- /* XXX: should check if same value is configured */
+ goto fail;
+ /* check that the same value is configured */
+ if (flags & JS_PROP_HAS_VALUE) {
+ if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
+ goto fail;
+ p2 = JS_VALUE_GET_STRING(val);
+ if (p2->len != 1)
+ goto fail;
+ if (string_get(p1, idx) != string_get(p2, 0)) {
+ fail:
+ return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
+ }
+ }
return TRUE;
} else {
def:
@@ -38578,12 +39026,14 @@ static int string_indexof(JSString *p1, JSString *p2, int from)
return -1;
}
-static int string_advance_index(JSString *p, int index, BOOL unicode)
+static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode)
{
- if (!unicode || (unsigned)index >= p->len || !p->is_wide_char) {
+ if (!unicode || index >= p->len || !p->is_wide_char) {
index++;
} else {
- string_getc(p, &index);
+ int index32 = (int)index;
+ string_getc(p, &index32);
+ index = index32;
}
return index;
}
@@ -38930,7 +39380,7 @@ static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val,
replacer = JS_GetProperty(ctx, searchValue, JS_ATOM_Symbol_replace);
if (JS_IsException(replacer))
return JS_EXCEPTION;
- if (!JS_IsUndefined(replacer)) {
+ if (!JS_IsUndefined(replacer) && !JS_IsNull(replacer)) {
args[0] = O;
args[1] = replaceValue;
return JS_CallFree(ctx, replacer, searchValue, 2, args);
@@ -40162,6 +40612,20 @@ static JSValue js___date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val
return JS_NewInt32(ctx, getTimezoneOffset((int64_t)dd));
}
+static JSValue js_get_prototype_from_ctor(JSContext *ctx, JSValueConst ctor,
+ JSValueConst def_proto)
+{
+ JSValue proto;
+ proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
+ if (JS_IsException(proto))
+ return proto;
+ if (!JS_IsObject(proto)) {
+ JS_FreeValue(ctx, proto);
+ proto = JS_DupValue(ctx, def_proto);
+ }
+ return proto;
+}
+
/* create a new date object */
static JSValue js___date_create(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -40531,13 +40995,14 @@ static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mas
if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
return JS_ThrowTypeErrorNotAnObject(ctx);
- if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
- return JS_UNDEFINED;
-
- re = js_get_regexp(ctx, this_val, TRUE);
- if (!re)
- return JS_EXCEPTION;
-
+ re = js_get_regexp(ctx, this_val, FALSE);
+ if (!re) {
+ if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
+ return JS_UNDEFINED;
+ else
+ return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
+ }
+
flags = lre_get_flags(re->bytecode->u.str8);
return JS_NewBool(ctx, (flags & mask) != 0);
}
@@ -40614,7 +41079,7 @@ fail:
BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)
{
JSContext *ctx = opaque;
- return js_check_stack_overflow(ctx, alloca_size);
+ return js_check_stack_overflow(ctx->rt, alloca_size);
}
void *lre_realloc(void *opaque, void *ptr, size_t size)
@@ -40753,7 +41218,7 @@ fail1:
return JS_EXCEPTION;
}
-/* delete partions of a string that match a given regex */
+/* delete portions of a string that match a given regex */
static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueConst arg)
{
JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
@@ -40952,9 +41417,7 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
goto exception;
p = JS_VALUE_GET_STRING(S);
- nextIndex = thisIndex + 1;
- if (thisIndex < p->len)
- nextIndex = string_advance_index(p, thisIndex, fullUnicode);
+ nextIndex = string_advance_index(p, thisIndex, fullUnicode);
if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
goto exception;
}
@@ -41043,7 +41506,7 @@ static JSValue js_regexp_string_iterator_next(JSContext *ctx,
sp = JS_VALUE_GET_STRING(S);
nextIndex = string_advance_index(sp, thisIndex, it->unicode);
if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex,
- JS_NewInt32(ctx, nextIndex)) < 0)
+ JS_NewInt64(ctx, nextIndex)) < 0)
goto exception;
}
JS_FreeValue(ctx, matchStr);
@@ -41096,7 +41559,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
JS_GetProperty(ctx, R, JS_ATOM_lastIndex)))
goto exception;
if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex,
- JS_NewInt32(ctx, lastIndex)) < 0)
+ JS_NewInt64(ctx, lastIndex)) < 0)
goto exception;
iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR);
@@ -41284,7 +41747,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
goto exception;
nextIndex = string_advance_index(sp, thisIndex, fullUnicode);
- if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, nextIndex)) < 0)
+ if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
goto exception;
}
}
@@ -41343,14 +41806,23 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
JS_FreeValue(ctx, rep_str);
rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0));
} else {
+ JSValue namedCaptures1;
+ if (!JS_IsUndefined(namedCaptures)) {
+ namedCaptures1 = JS_ToObject(ctx, namedCaptures);
+ if (JS_IsException(namedCaptures1))
+ goto exception;
+ } else {
+ namedCaptures1 = JS_UNDEFINED;
+ }
args[0] = matched;
args[1] = str;
args[2] = JS_NewInt32(ctx, position);
args[3] = tab;
- args[4] = namedCaptures;
+ args[4] = namedCaptures1;
args[5] = rep_val;
JS_FreeValue(ctx, rep_str);
rep_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
+ JS_FreeValue(ctx, namedCaptures1);
}
if (JS_IsException(rep_str))
goto exception;
@@ -41790,7 +42262,7 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
JSAtom prop;
JSPropertyEnum *atoms = NULL;
- if (js_check_stack_overflow(ctx, 0)) {
+ if (js_check_stack_overflow(ctx->rt, 0)) {
return JS_ThrowStackOverflow(ctx);
}
@@ -42516,7 +42988,7 @@ static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
JSValue method;
/* safer to test recursion in all proxy methods */
- if (js_check_stack_overflow(ctx, 0)) {
+ if (js_check_stack_overflow(ctx->rt, 0)) {
JS_ThrowStackOverflow(ctx);
return NULL;
}
@@ -43346,14 +43818,6 @@ static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT ||
JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT)
return JS_ThrowTypeErrorNotAnObject(ctx);
- s = JS_GetOpaque(target, JS_CLASS_PROXY);
- if (s && s->is_revoked)
- goto revoked_proxy;
- s = JS_GetOpaque(handler, JS_CLASS_PROXY);
- if (s && s->is_revoked) {
- revoked_proxy:
- return JS_ThrowTypeErrorRevokedProxy(ctx);
- }
obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY);
if (JS_IsException(obj))
@@ -44872,14 +45336,18 @@ static __exception int remainingElementsCount_add(JSContext *ctx,
return (remainingElementsCount == 0);
}
+#define PROMISE_MAGIC_all 0
+#define PROMISE_MAGIC_allSettled 1
+#define PROMISE_MAGIC_any 2
+
static JSValue js_promise_all_resolve_element(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv,
int magic,
JSValue *func_data)
{
- int is_allSettled = magic & 1;
- int is_reject = magic & 2;
+ int resolve_type = magic & 3;
+ int is_reject = magic & 4;
BOOL alreadyCalled = JS_ToBool(ctx, func_data[0]);
JSValueConst values = func_data[2];
JSValueConst resolve = func_data[3];
@@ -44893,7 +45361,7 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx,
return JS_UNDEFINED;
func_data[0] = JS_NewBool(ctx, TRUE);
- if (is_allSettled) {
+ if (resolve_type == PROMISE_MAGIC_allSettled) {
JSValue str;
obj = JS_NewObject(ctx);
@@ -44925,7 +45393,16 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx,
if (is_zero < 0)
return JS_EXCEPTION;
if (is_zero) {
- ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);
+ if (resolve_type == PROMISE_MAGIC_any) {
+ JSValue error;
+ error = js_aggregate_error_constructor(ctx, values);
+ if (JS_IsException(error))
+ return JS_EXCEPTION;
+ ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error);
+ JS_FreeValue(ctx, error);
+ } else {
+ ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);
+ }
if (JS_IsException(ret))
return ret;
JS_FreeValue(ctx, ret);
@@ -44942,8 +45419,8 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element;
JSValue promise_resolve = JS_UNDEFINED;
JSValueConst then_args[2], resolve_element_data[5];
- BOOL done, is_allSettled = magic;
- int index, is_zero;
+ BOOL done;
+ int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any);
if (!JS_IsObject(this_val))
return JS_ThrowTypeErrorNotAnObject(ctx);
@@ -45002,24 +45479,30 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
resolve_element_data[0] = JS_NewBool(ctx, FALSE);
resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);
resolve_element_data[2] = values;
- resolve_element_data[3] = resolving_funcs[0];
+ resolve_element_data[3] = resolving_funcs[is_promise_any];
resolve_element_data[4] = resolve_element_env;
resolve_element =
JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
- is_allSettled, 5, resolve_element_data);
+ magic, 5, resolve_element_data);
if (JS_IsException(resolve_element)) {
JS_FreeValue(ctx, next_promise);
goto fail_reject1;
}
- if (is_allSettled) {
+ if (magic == PROMISE_MAGIC_allSettled) {
reject_element =
JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
- is_allSettled | 2, 5, resolve_element_data);
+ magic | 4, 5, resolve_element_data);
if (JS_IsException(reject_element)) {
JS_FreeValue(ctx, next_promise);
goto fail_reject1;
}
+ } else if (magic == PROMISE_MAGIC_any) {
+ if (JS_DefinePropertyValueUint32(ctx, values, index,
+ JS_UNDEFINED, JS_PROP_C_W_E) < 0)
+ goto fail_reject1;
+ reject_element = resolve_element;
+ resolve_element = JS_DupValue(ctx, resolving_funcs[0]);
} else {
reject_element = JS_DupValue(ctx, resolving_funcs[1]);
}
@@ -45045,7 +45528,15 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
if (is_zero < 0)
goto fail_reject;
if (is_zero) {
- ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
+ if (magic == PROMISE_MAGIC_any) {
+ JSValue error;
+ error = js_aggregate_error_constructor(ctx, values);
+ if (JS_IsException(error))
+ goto fail_reject;
+ JS_FreeValue(ctx, values);
+ values = error;
+ }
+ ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,
1, (JSValueConst *)&values);
if (check_exception_free(ctx, ret))
goto fail_reject;
@@ -45323,8 +45814,9 @@ static JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val,
static const JSCFunctionListEntry js_promise_funcs[] = {
JS_CFUNC_MAGIC_DEF("resolve", 1, js_promise_resolve, 0 ),
JS_CFUNC_MAGIC_DEF("reject", 1, js_promise_resolve, 1 ),
- JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, 0 ),
- JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, 1 ),
+ JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, PROMISE_MAGIC_all ),
+ JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ),
+ JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ),
JS_CFUNC_DEF("race", 1, js_promise_race ),
//JS_CFUNC_DEF("__newPromiseCapability", 1, js_promise___newPromiseCapability ),
JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
@@ -45459,7 +45951,8 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi
goto done_resolve;
}
}
- value = JS_IteratorNext2(ctx, s->sync_iter, method, 1, argv, &done);
+ value = JS_IteratorNext2(ctx, s->sync_iter, method,
+ argc >= 1 ? 1 : 0, argv, &done);
JS_FreeValue(ctx, method);
if (JS_IsException(value))
goto reject;
@@ -48852,7 +49345,7 @@ void JS_EnableBignumExt(JSContext *ctx, BOOL enable)
static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = {
"EvalError", "RangeError", "ReferenceError",
"SyntaxError", "TypeError", "URIError",
- "InternalError",
+ "InternalError", "AggregateError",
};
/* Minimum amount of objects to be able to compile code and display
@@ -48892,6 +49385,9 @@ static void JS_AddIntrinsicBasicObjects(JSContext *ctx)
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
ctx->native_error_proto[i] = proto;
}
+ JS_SetPropertyFunctionList(ctx, ctx->native_error_proto[JS_AGGREGATE_ERROR],
+ js_aggregate_error_proto_funcs,
+ countof(js_aggregate_error_proto_funcs));
/* the array prototype is an array */
ctx->class_proto[JS_CLASS_ARRAY] =
@@ -48957,9 +49453,12 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
"Error", ctx->class_proto[JS_CLASS_ERROR]);
for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
- JSValue func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_error_constructor,
- native_error_name[i], 1,
- JS_CFUNC_constructor_or_func_magic, i, obj1);
+ JSValue func_obj;
+ int n_args;
+ n_args = 1 + (i == JS_AGGREGATE_ERROR);
+ func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_error_constructor,
+ native_error_name[i], n_args,
+ JS_CFUNC_constructor_or_func_magic, i, obj1);
JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i],
ctx->native_error_proto[i]);
}
@@ -48977,6 +49476,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
obj = JS_NewGlobalCConstructor(ctx, "Array", js_array_constructor, 1,
ctx->class_proto[JS_CLASS_ARRAY]);
+ ctx->array_ctor = JS_DupValue(ctx, obj);
JS_SetPropertyFunctionList(ctx, obj, js_array_funcs,
countof(js_array_funcs));
@@ -49004,6 +49504,12 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
js_array_iterator_proto_funcs,
countof(js_array_iterator_proto_funcs));
+ /* parseFloat and parseInteger must be defined before Number
+ because of the Number.parseFloat and Number.parseInteger
+ aliases */
+ JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs,
+ countof(js_global_funcs));
+
/* Number */
ctx->class_proto[JS_CLASS_NUMBER] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
JS_CLASS_NUMBER);
@@ -49093,9 +49599,6 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
JS_DupValue(ctx, ctx->eval_obj),
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs,
- countof(js_global_funcs));
-
JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis,
JS_DupValue(ctx, ctx->global_obj),
JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
diff --git a/quickjs.h b/quickjs.h
index abf4d83..f6bfdb0 100644
--- a/quickjs.h
+++ b/quickjs.h
@@ -333,6 +333,7 @@ JSRuntime *JS_NewRuntime(void);
void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
+void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size);
JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque);
void JS_FreeRuntime(JSRuntime *rt);
void *JS_GetRuntimeOpaque(JSRuntime *rt);
@@ -344,10 +345,10 @@ JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj);
JSContext *JS_NewContext(JSRuntime *rt);
void JS_FreeContext(JSContext *s);
+JSContext *JS_DupContext(JSContext *ctx);
void *JS_GetContextOpaque(JSContext *ctx);
void JS_SetContextOpaque(JSContext *ctx, void *opaque);
JSRuntime *JS_GetRuntime(JSContext *ctx);
-void JS_SetMaxStackSize(JSContext *ctx, size_t stack_size);
void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj);
JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id);
@@ -673,7 +674,7 @@ static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */
int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val);
-static int inline JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
+static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
{
return JS_ToInt32(ctx, (int32_t*)pres, val);
}
diff --git a/run-test262.c b/run-test262.c
index 8eeecd1..d5b6e81 100644
--- a/run-test262.c
+++ b/run-test262.c
@@ -1,8 +1,8 @@
/*
* ECMA Test 262 Runner for QuickJS
*
- * Copyright (c) 2017-2018 Fabrice Bellard
- * Copyright (c) 2017-2018 Charlie Gordon
+ * Copyright (c) 2017-2020 Fabrice Bellard
+ * Copyright (c) 2017-2020 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -41,8 +41,6 @@
/* enable test262 thread support to test SharedArrayBuffer and Atomics */
#define CONFIG_AGENT
-/* cross-realm tests (not supported yet) */
-//#define CONFIG_REALM
#define CMD_NAME "run-test262"
@@ -730,18 +728,20 @@ static JSValue js_new_agent(JSContext *ctx)
}
#endif
-#ifdef CONFIG_REALM
static JSValue js_createRealm(JSContext *ctx, JSValue this_val,
int argc, JSValue *argv)
{
JSContext *ctx1;
- /* XXX: the context is not freed, need a refcount */
+ JSValue ret;
+
ctx1 = JS_NewContext(JS_GetRuntime(ctx));
if (!ctx1)
return JS_ThrowOutOfMemory(ctx);
- return add_helpers1(ctx1);
+ ret = add_helpers1(ctx1);
+ /* ctx1 has a refcount so it stays alive */
+ JS_FreeContext(ctx1);
+ return ret;
}
-#endif
static JSValue add_helpers1(JSContext *ctx)
{
@@ -770,12 +770,9 @@ static JSValue add_helpers1(JSContext *ctx)
JS_SetPropertyStr(ctx, obj262, "global",
JS_DupValue(ctx, global_obj));
-
-#ifdef CONFIG_REALM
JS_SetPropertyStr(ctx, obj262, "createRealm",
JS_NewCFunction(ctx, js_createRealm,
"createRealm", 0));
-#endif
JS_SetPropertyStr(ctx, global_obj, "$262", JS_DupValue(ctx, obj262));
diff --git a/test262.conf b/test262.conf
index b6d3852..4971dd8 100644
--- a/test262.conf
+++ b/test262.conf
@@ -48,7 +48,7 @@ testdir=test262/test
# list the features that are included
# skipped features are tagged as such to avoid warnings
-AggregateError=skip
+AggregateError
Array.prototype.flat
Array.prototype.flatMap
Array.prototype.flatten
@@ -70,7 +70,7 @@ class-static-methods-private
coalesce-expression
computed-property-names
const
-cross-realm=skip
+cross-realm
DataView
DataView.prototype.getFloat32
DataView.prototype.getFloat64
@@ -102,6 +102,7 @@ Int8Array
IsHTMLDDA=skip
json-superset
let
+logical-assignment-operators=skip
Map
new.target
numeric-separator-literal
@@ -112,6 +113,7 @@ Object.is
optional-catch-binding
optional-chaining
Promise.allSettled
+Promise.any
Promise.prototype.finally
Proxy
proxy-missing-checks
@@ -179,5 +181,8 @@ test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
#test262/test/built-ins/RegExp/CharacterClassEscapes/
#test262/test/built-ins/RegExp/property-escapes/
+# invalid tests
+test262/test/language/module-code/verify-dfs.js
+
[tests]
# list test files or use config.testdir
diff --git a/test262_errors.txt b/test262_errors.txt
index 41521ae..024f357 100644
--- a/test262_errors.txt
+++ b/test262_errors.txt
@@ -1,9 +1,15 @@
+test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: Test262Error: Expected a ReferenceError but got a ReferenceError
+test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError
+test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
+test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: strict mode: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
test262/test/language/expressions/arrow-function/eval-var-scope-syntax-err.js:47: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/expressions/async-arrow-function/eval-var-scope-syntax-err.js:49: TypeError: $DONE() not called
test262/test/language/expressions/async-function/named-eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
test262/test/language/expressions/async-function/nameless-eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
test262/test/language/expressions/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/expressions/async-generator/named-eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
+test262/test/language/expressions/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name
+test262/test/language/expressions/class/elements/grammar-private-field-optional-chaining.js:26: strict mode: SyntaxError: expecting field name
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
test262/test/language/expressions/function/eval-var-scope-syntax-err.js:48: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
@@ -16,7 +22,7 @@ test262/test/language/expressions/optional-chaining/optional-call-preserves-this
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: value has no property
test262/test/language/statements/async-function/eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
test262/test/language/statements/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
-test262/test/language/statements/for-await-of/async-gen-decl-dstr-array-elem-iter-rtrn-close-null.js:81: TypeError: $DONE() not called
-test262/test/language/statements/for-await-of/async-gen-decl-dstr-array-elem-iter-rtrn-close-null.js:81: strict mode: TypeError: $DONE() not called
+test262/test/language/statements/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name
+test262/test/language/statements/class/elements/grammar-private-field-optional-chaining.js:26: strict mode: SyntaxError: expecting field name
test262/test/language/statements/function/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/statements/generators/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
diff --git a/tests/test_std.js b/tests/test_std.js
index 94a4d2a..54917c9 100644
--- a/tests/test_std.js
+++ b/tests/test_std.js
@@ -214,7 +214,11 @@ function test_os_exec()
assert(ret, 1);
fds = os.pipe();
- pid = os.exec(["echo", "hello"], { stdout: fds[1], block: false } );
+ pid = os.exec(["sh", "-c", "echo $FOO"], {
+ stdout: fds[1],
+ block: false,
+ env: { FOO: "hello" },
+ } );
assert(pid >= 0);
os.close(fds[1]); /* close the write end (as it is only in the child) */
f = std.fdopen(fds[0], "r");