From d3da56b6304fa245fbc12d744ecfdcfdfdb292c8 Mon Sep 17 00:00:00 2001 From: Tom Lienard Date: Mon, 22 Apr 2024 10:36:50 +0100 Subject: [PATCH] Sync TLA implementation with upstream Fixes: https://github.com/quickjs-ng/quickjs/issues/339 --- doc/quickjs.texi | 11 + gen/hello_module.c | Bin 3953 -> 3965 bytes gen/repl.c | Bin 137820 -> 139210 bytes gen/test_fib.c | Bin 1948 -> 1954 bytes qjs.c | 1 + quickjs-libc.c | 88 ++++- quickjs-libc.h | 1 + quickjs.c | 800 +++++++++++++++++++++++++++++++++++---------- quickjs.h | 30 +- repl.js | 102 +++--- run-test262.c | 79 +++-- 11 files changed, 848 insertions(+), 264 deletions(-) diff --git a/doc/quickjs.texi b/doc/quickjs.texi index 8d8fdd7..dab92bf 100644 --- a/doc/quickjs.texi +++ b/doc/quickjs.texi @@ -330,6 +330,11 @@ optional properties: @item backtrace_barrier Boolean (default = false). If true, error backtraces do not list the stack frames below the evalScript. + @item async + Boolean (default = false). If true, @code{await} is accepted in the + script and a promise is returned. The promise is resolved with an + object whose @code{value} property holds the value returned by the + script. @end table @item loadScript(filename) @@ -717,6 +722,12 @@ write_fd]} or null in case of error. @item sleep(delay_ms) Sleep during @code{delay_ms} milliseconds. +@item sleepAsync(delay_ms) +Asynchronouse sleep during @code{delay_ms} milliseconds. Returns a promise. Example: +@example +await os.sleepAsync(500); +@end example + @item setTimeout(func, delay) Call the function @code{func} after @code{delay} ms. Return a handle to the timer. diff --git a/gen/hello_module.c b/gen/hello_module.c index b1ce18be5cfad835dbedab762a4084e2647450a8..be72121c3e9e4e37572d8fdd12ffe35190cad086 100644 GIT binary patch delta 552 zcmYk3J4*vW6or{}ch>AiZCn!)3Bd>AI>jWLtP$)4u@ws&K}@0+f?A2Kk5*96p9nT0 zX{^LYA&LlsjlEciAc0hZ;GKO0i(L-i+S`zq)be$X~x z1&;pdt4J4!f5*Hgkk`XrpZw=zO+Nd&iw&N_ogVH~q&e>a8-O&D^!3r!uYAn%q@W~T zRaj^lX`J(fEq*z%gwIEb?CL7-h5#hnmwtLN)D~ zt9#i?IOsLA0rd(3(p2=CYPTaQR|HPYFhy}n;4adVs@vuQt6;8slvSFW-7}gK>?(uB zXogyBjoPoR=mM#w73+$?kgbN@*dskuC`&3%eU)-9+YVr7x$3Xi@Ir6*Xgi&^`>-QB bN|8#sxHZSw3ck!V4wCsWi4@JVwJ?iV delta 605 zcmYk4JxIeq7>2p@a!Hfg7Jpjtr}%>kA;=}wXwgMn#l=Bzk=m-0P7dzk?9aOt2f@uv zq#!s5B7zP|7tzt(NmrrZce#Qca(Vdf<$b@q@0x|5!tnuLgdG!e_I zN*-vIA@N3wBVx4iW5Vm8sDSD!vEpNh_aMtNacG6q<2-hZRM0B-ux8~^<9&D%Srklx zXWp;0p-TLseO)gg5I%NI8=GPd4}2JdR+1O1B>FTxTnT|!;gCTuK17B&SP&l4<^XDD z#wELGI=-7Su6Z8P?4&PAsyE?vsa@S}R8pcS^ij4(5&?NfR@`hjOT4XFmWgYYXR0Pk zSW0=xNZ&ivf2|cZLxUP)Gxa@t(ZDTBQ_PE_FI`zSTdXW6U0qjaU2o%KH@2@O-4Jenqfw&y{Q#KEE7FOs%?lX^1#0G%L} AmjD0& diff --git a/gen/repl.c b/gen/repl.c index 5b01bc4d99176941e883984274a904647d4c5324..2757a668f697addeb14cef4c2349972b9fdba168 100644 GIT binary patch literal 139210 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 c`}Hc_2t=AFO}@NEC82&tauV+Q%ij2&2?pKtt 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

fOWTe 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 ar=|kMl~^F=8UxwEP= 2) { @@ -785,6 +786,9 @@ static JSValue js_evalScript(JSContext *ctx, JSValue this_val, if (get_bool_option(ctx, &backtrace_barrier, options_obj, "backtrace_barrier")) return JS_EXCEPTION; + if (get_bool_option(ctx, &is_async, options_obj, + "async")) + return JS_EXCEPTION; } str = JS_ToCStringLen(ctx, &len, argv[0]); @@ -797,6 +801,8 @@ static JSValue js_evalScript(JSContext *ctx, JSValue this_val, flags = JS_EVAL_TYPE_GLOBAL; if (backtrace_barrier) flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER; + if (is_async) + flags |= JS_EVAL_FLAG_ASYNC; ret = JS_Eval(ctx, str, len, "", flags); JS_FreeCString(ctx, str); if (!ts->recv_pipe && --ts->eval_script_recurse == 0) { @@ -2114,6 +2120,38 @@ static JSClassDef js_os_timer_class = { .gc_mark = js_os_timer_mark, }; +/* return a promise */ +static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + int64_t delay; + JSOSTimer *th; + JSValue promise, resolving_funcs[2]; + + if (JS_ToInt64(ctx, &delay, argv[0])) + return JS_EXCEPTION; + promise = JS_NewPromiseCapability(ctx, resolving_funcs); + if (JS_IsException(promise)) + return JS_EXCEPTION; + + th = js_mallocz(ctx, sizeof(*th)); + if (!th) { + JS_FreeValue(ctx, promise); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return JS_EXCEPTION; + } + th->has_object = FALSE; + th->timeout = js__hrtime_ms() + delay; + th->func = JS_DupValue(ctx, resolving_funcs[0]); + list_add_tail(&th->link, &ts->os_timers); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return promise; +} + static void call_handler(JSContext *ctx, JSValue func) { JSValue ret, func1; @@ -3329,6 +3367,7 @@ static void *worker_func(void *opaque) JSRuntime *rt; JSThreadState *ts; JSContext *ctx; + JSValue val; rt = JS_NewRuntime(); if (rt == NULL) { @@ -3355,11 +3394,14 @@ static void *worker_func(void *opaque) js_std_add_helpers(ctx, -1, NULL); - if (!JS_RunModule(ctx, args->basename, args->filename)) - js_std_dump_error(ctx); + val = JS_LoadModule(ctx, args->basename, args->filename); free(args->filename); free(args->basename); free(args); + val = js_std_await(ctx, val); + if (JS_IsException(val)) + js_std_dump_error(ctx); + JS_FreeValue(ctx, val); js_std_loop(ctx); @@ -3702,6 +3744,7 @@ static const JSCFunctionListEntry js_os_funcs[] = { // per spec: both functions can cancel timeouts and intervals JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ), JS_CFUNC_DEF("clearInterval", 1, js_os_clearTimeout ), + JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ), JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ), JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ), JS_CFUNC_DEF("chdir", 0, js_os_chdir ), @@ -3980,6 +4023,42 @@ void js_std_loop(JSContext *ctx) } } +/* Wait for a promise and execute pending jobs while waiting for + it. Return the promise result or JS_EXCEPTION in case of promise + rejection. */ +JSValue js_std_await(JSContext *ctx, JSValue obj) +{ + JSValue ret; + int state; + + for(;;) { + state = JS_PromiseState(ctx, obj); + if (state == JS_PROMISE_FULFILLED) { + ret = JS_PromiseResult(ctx, obj); + JS_FreeValue(ctx, obj); + break; + } else if (state == JS_PROMISE_REJECTED) { + ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj)); + JS_FreeValue(ctx, obj); + break; + } else if (state == JS_PROMISE_PENDING) { + JSContext *ctx1; + int err; + err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + if (err < 0) { + js_std_dump_error(ctx1); + } + if (os_poll_func) + os_poll_func(ctx); + } else { + /* not a promise */ + ret = obj; + break; + } + } + return ret; +} + void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, int load_only) { @@ -3998,8 +4077,11 @@ void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, goto exception; } js_module_set_import_meta(ctx, obj, FALSE, TRUE); + val = JS_EvalFunction(ctx, obj); + val = js_std_await(ctx, val); + } else { + val = JS_EvalFunction(ctx, obj); } - val = JS_EvalFunction(ctx, obj); if (JS_IsException(val)) { exception: js_std_dump_error(ctx); diff --git a/quickjs-libc.h b/quickjs-libc.h index f8e31d4..ad850a3 100644 --- a/quickjs-libc.h +++ b/quickjs-libc.h @@ -37,6 +37,7 @@ JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); void js_std_add_helpers(JSContext *ctx, int argc, char **argv); void js_std_loop(JSContext *ctx); +JSValue js_std_await(JSContext *ctx, JSValue obj); void js_std_init_handlers(JSRuntime *rt); void js_std_free_handlers(JSRuntime *rt); void js_std_dump_error(JSContext *ctx); diff --git a/quickjs.c b/quickjs.c index 946819c..6f4ce15 100644 --- a/quickjs.c +++ b/quickjs.c @@ -264,6 +264,8 @@ struct JSRuntime { JSModuleNormalizeFunc *module_normalize_func; JSModuleLoaderFunc *module_loader_func; void *module_loader_opaque; + /* timestamp for internal use in module evaluation */ + int64_t module_async_evaluation_next_timestamp; /* used to allocate, free and clone SharedArrayBuffers */ JSSharedArrayBufferFunctions sab_funcs; @@ -758,6 +760,15 @@ typedef struct JSImportEntry { int req_module_idx; /* in req_module_entries */ } JSImportEntry; +typedef enum { + JS_MODULE_STATUS_UNLINKED, + JS_MODULE_STATUS_LINKING, + JS_MODULE_STATUS_LINKED, + JS_MODULE_STATUS_EVALUATING, + JS_MODULE_STATUS_EVALUATING_ASYNC, + JS_MODULE_STATUS_EVALUATED, +} JSModuleStatus; + struct JSModuleDef { JSRefCountHeader header; /* must come first, 32-bit */ JSAtom module_name; @@ -779,15 +790,26 @@ struct JSModuleDef { int import_entries_count; int import_entries_size; - JSValue promise; JSValue module_ns; JSValue func_obj; /* only used for JS modules */ JSModuleInitFunc *init_func; /* only used for C modules */ + BOOL has_tla : 8; /* true if func_obj contains await */ BOOL resolved : 8; BOOL func_created : 8; - BOOL instantiated : 8; - BOOL evaluated : 8; - BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */ + JSModuleStatus status : 8; + /* temp use during js_module_link() & js_module_evaluate() */ + int dfs_index, dfs_ancestor_index; + JSModuleDef *stack_prev; + /* temp use during js_module_evaluate() */ + JSModuleDef **async_parent_modules; + int async_parent_modules_count; + int async_parent_modules_size; + int pending_async_dependencies; + BOOL async_evaluation; + int64_t async_evaluation_timestamp; + JSModuleDef *cycle_root; + JSValue promise; /* corresponds to spec field: capability */ + JSValue resolving_funcs[2]; /* corresponds to spec field: capability */ /* true if evaluation yielded an exception. It is saved in eval_exception */ BOOL eval_has_exception : 8; @@ -852,14 +874,6 @@ struct JSShape { JSShapeProperty prop[0]; /* prop_size elements */ }; -typedef struct JSPromiseData { - JSPromiseStateEnum promise_state; - /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */ - struct list_head promise_reactions[2]; - BOOL is_handled; /* Note: only useful to debug */ - JSValue promise_result; -} JSPromiseData; - struct JSObject { union { JSGCObjectHeader header; @@ -1102,12 +1116,8 @@ static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValue ctor, static void gc_decref(JSRuntime *rt); static int JS_NewClass1(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def, JSAtom name); -static JSValue js_promise_all(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv, int magic); -static JSValue js_promise_then(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv); -static JSValue js_array_push(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv, int unshift); +static JSValue js_array_push(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int unshift); typedef enum JSStrictEqModeEnum { JS_EQ_STRICT, @@ -1197,6 +1207,8 @@ static __exception int perform_promise_then(JSContext *ctx, JSValue *cap_resolving_funcs); static JSValue js_promise_resolve(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic); +static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv); static int js_string_compare(JSContext *ctx, const JSString *p1, const JSString *p2); static JSValue JS_ToNumber(JSContext *ctx, JSValue val); @@ -2187,7 +2199,6 @@ JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id) typedef enum JSFreeModuleEnum { JS_FREE_MODULE_ALL, JS_FREE_MODULE_NOT_RESOLVED, - JS_FREE_MODULE_NOT_EVALUATED, } JSFreeModuleEnum; /* XXX: would be more efficient with separate module lists */ @@ -2197,9 +2208,7 @@ static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag) list_for_each_safe(el, el1, &ctx->loaded_modules) { JSModuleDef *m = list_entry(el, JSModuleDef, link); if (flag == JS_FREE_MODULE_ALL || - (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved) || - (flag == JS_FREE_MODULE_NOT_EVALUATED && !m->evaluated - && !m->eval_mark)) { + (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) { js_free_module_def(ctx, m); } } @@ -18474,6 +18483,7 @@ typedef struct JSFunctionDef { int source_len; JSModuleDef *module; /* != NULL when parsing a module */ + BOOL has_await; /* TRUE if await is used (used in module eval) */ JSInlineCache *ic; /* inline cache for field op */ } JSFunctionDef; @@ -23711,6 +23721,7 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags) return -1; if (js_parse_unary(s, PF_POW_FORBIDDEN)) return -1; + s->cur_func->has_await = TRUE; emit_op(s, OP_await); parse_flags = 0; break; @@ -25138,6 +25149,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, is_async = TRUE; if (next_token(s)) goto fail; + s->cur_func->has_await = TRUE; } if (js_parse_expect(s, '(')) goto fail; @@ -25666,11 +25678,13 @@ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name) } m->header.ref_count = 1; m->module_name = name; - m->promise = JS_UNDEFINED; m->module_ns = JS_UNDEFINED; m->func_obj = JS_UNDEFINED; m->eval_exception = JS_UNDEFINED; m->meta_obj = JS_UNDEFINED; + m->promise = JS_UNDEFINED; + m->resolving_funcs[0] = JS_UNDEFINED; + m->resolving_funcs[1] = JS_UNDEFINED; list_add_tail(&m->link, &ctx->loaded_modules); return m; } @@ -25688,11 +25702,13 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, } } - JS_MarkValue(rt, m->promise, mark_func); 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); + JS_MarkValue(rt, m->promise, mark_func); + JS_MarkValue(rt, m->resolving_funcs[0], mark_func); + JS_MarkValue(rt, m->resolving_funcs[1], mark_func); } static void js_free_module_def(JSContext *ctx, JSModuleDef *m) @@ -25723,12 +25739,15 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m) JS_FreeAtom(ctx, mi->import_name); } js_free(ctx, m->import_entries); + js_free(ctx, m->async_parent_modules); - JS_FreeValue(ctx, m->promise); JS_FreeValue(ctx, m->module_ns); JS_FreeValue(ctx, m->func_obj); JS_FreeValue(ctx, m->eval_exception); JS_FreeValue(ctx, m->meta_obj); + JS_FreeValue(ctx, m->promise); + JS_FreeValue(ctx, m->resolving_funcs[0]); + JS_FreeValue(ctx, m->resolving_funcs[1]); list_del(&m->link); js_free(ctx, m); } @@ -26596,7 +26615,8 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) /* Prepare a module to be executed by resolving all the imported variables. */ -static int js_link_module(JSContext *ctx, JSModuleDef *m) +static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, + JSModuleDef **pstack_top, int index) { int i; JSImportEntry *mi; @@ -26606,21 +26626,47 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m) BOOL is_c_module; JSValue ret_val; - if (m->instantiated) - return 0; - m->instantiated = TRUE; + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + return -1; + } #ifdef DUMP_MODULE_RESOLVE if (check_dump_flag(ctx->rt, DUMP_MODULE_RESOLVE)) { char buf1[ATOM_GET_STR_BUF_SIZE]; - printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); + printf("js_inner_module_linking '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); } #endif + if (m->status == JS_MODULE_STATUS_LINKING || + m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED) + return index; + + assert(m->status == JS_MODULE_STATUS_UNLINKED); + m->status = JS_MODULE_STATUS_LINKING; + m->dfs_index = index; + m->dfs_ancestor_index = index; + index++; + /* push 'm' on stack */ + m->stack_prev = *pstack_top; + *pstack_top = m; + for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; - if (js_link_module(ctx, rme->module) < 0) + m1 = rme->module; + index = js_inner_module_linking(ctx, m1, pstack_top, index); + if (index < 0) goto fail; + assert(m1->status == JS_MODULE_STATUS_LINKING || + m1->status == JS_MODULE_STATUS_LINKED || + m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m1->status == JS_MODULE_STATUS_EVALUATED); + if (m1->status == JS_MODULE_STATUS_LINKING) { + m->dfs_ancestor_index = min_int(m->dfs_ancestor_index, + m1->dfs_ancestor_index); + } } #ifdef DUMP_MODULE_RESOLVE @@ -26747,13 +26793,59 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m) JS_FreeValue(ctx, ret_val); } - module_trace(ctx, "done instantiate\n"); + assert(m->dfs_ancestor_index <= m->dfs_index); + if (m->dfs_index == m->dfs_ancestor_index) { + for(;;) { + /* pop m1 from stack */ + m1 = *pstack_top; + *pstack_top = m1->stack_prev; + m1->status = JS_MODULE_STATUS_LINKED; + if (m1 == m) + break; + } + } - return 0; +#ifdef DUMP_MODULE_RESOLVE + printf("js_inner_module_linking done\n"); +#endif + return index; fail: return -1; } +/* Prepare a module to be executed by resolving all the imported + variables. */ +static int js_link_module(JSContext *ctx, JSModuleDef *m) +{ + JSModuleDef *stack_top, *m1; + +#ifdef DUMP_MODULE_RESOLVE + { + char buf1[ATOM_GET_STR_BUF_SIZE]; + printf("js_link_module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); + } +#endif + assert(m->status == JS_MODULE_STATUS_UNLINKED || + m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + stack_top = NULL; + if (js_inner_module_linking(ctx, m, &stack_top, 0) < 0) { + while (stack_top != NULL) { + m1 = stack_top; + assert(m1->status == JS_MODULE_STATUS_LINKING); + m1->status = JS_MODULE_STATUS_UNLINKED; + stack_top = m1->stack_prev; + } + return -1; + } + assert(stack_top == NULL); + assert(m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + return 0; +} + /* return JS_ATOM_NULL if the name cannot be found. Only works with not striped bytecode functions. */ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels) @@ -26821,41 +26913,110 @@ static JSValue js_import_meta(JSContext *ctx) return JS_GetImportMeta(ctx, m); } -/* used by os.Worker() and import() */ -JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, - const char *filename) +static JSValue JS_NewModuleValue(JSContext *ctx, JSModuleDef *m) { + return JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); +} + +static JSValue js_load_module_rejected(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) +{ + JSValueConst *resolving_funcs = (JSValueConst *)func_data; + JSValueConst error; + JSValue ret; + + /* XXX: check if the test is necessary */ + if (argc >= 1) + error = argv[0]; + else + error = JS_UNDEFINED; + ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, + 1, &error); + JS_FreeValue(ctx, ret); + return JS_UNDEFINED; +} + +static JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) +{ + JSValueConst *resolving_funcs = (JSValueConst *)func_data; + JSModuleDef *m = JS_VALUE_GET_PTR(func_data[2]); + JSValue ret, ns; + + /* return the module namespace */ + ns = JS_GetModuleNamespace(ctx, m); + if (JS_IsException(ns)) { + JSValue err = JS_GetException(ctx); + js_load_module_rejected(ctx, JS_UNDEFINED, 1, (JSValueConst *)&err, 0, func_data); + return JS_UNDEFINED; + } + ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, + 1, (JSValueConst *)&ns); + JS_FreeValue(ctx, ret); + JS_FreeValue(ctx, ns); + return JS_UNDEFINED; +} + +static void JS_LoadModuleInternal(JSContext *ctx, const char *basename, + const char *filename, + JSValueConst *resolving_funcs) +{ + JSValue evaluate_promise; JSModuleDef *m; - JSValue ret, func_obj; + JSValue ret, err, func_obj, evaluate_resolving_funcs[2]; + JSValueConst func_data[3]; m = js_host_resolve_imported_module(ctx, basename, filename); if (!m) - return NULL; + goto fail; if (js_resolve_module(ctx, m) < 0) { js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED); - return NULL; + goto fail; } /* Evaluate the module code */ - func_obj = js_dup(JS_MKPTR(JS_TAG_MODULE, m)); - ret = JS_EvalFunction(ctx, func_obj); - if (JS_IsException(ret)) - return NULL; + func_obj = JS_NewModuleValue(ctx, m); + evaluate_promise = JS_EvalFunction(ctx, func_obj); + if (JS_IsException(evaluate_promise)) { + fail: + 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); + return; + } + + func_obj = JS_NewModuleValue(ctx, m); + func_data[0] = resolving_funcs[0]; + func_data[1] = resolving_funcs[1]; + func_data[2] = func_obj; + evaluate_resolving_funcs[0] = JS_NewCFunctionData(ctx, js_load_module_fulfilled, 0, 0, 3, func_data); + evaluate_resolving_funcs[1] = JS_NewCFunctionData(ctx, js_load_module_rejected, 0, 0, 3, func_data); + JS_FreeValue(ctx, func_obj); + ret = js_promise_then(ctx, evaluate_promise, 2, (JSValueConst *)evaluate_resolving_funcs); JS_FreeValue(ctx, ret); - return m; + JS_FreeValue(ctx, evaluate_resolving_funcs[0]); + JS_FreeValue(ctx, evaluate_resolving_funcs[1]); + JS_FreeValue(ctx, evaluate_promise); } -static JSValue js_dynamic_import_resolve(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv, int magic, JSValue *func_data) +/* Return a promise or an exception in case of memory error. Used by + os.Worker() */ +JSValue JS_LoadModule(JSContext *ctx, const char *basename, + const char *filename) { - return JS_Call(ctx, func_data[0], JS_UNDEFINED, 1, &func_data[2]); -} + JSValue promise, resolving_funcs[2]; -static JSValue js_dynamic_import_reject(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv, int magic, JSValue *func_data) -{ - return JS_Call(ctx, func_data[1], JS_UNDEFINED, 1, &argv[0]); + promise = JS_NewPromiseCapability(ctx, resolving_funcs); + if (JS_IsException(promise)) + return JS_EXCEPTION; + JS_LoadModuleInternal(ctx, basename, filename, + (JSValueConst *)resolving_funcs); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return promise; } static JSValue js_dynamic_import_job(JSContext *ctx, @@ -26866,7 +27027,7 @@ static JSValue js_dynamic_import_job(JSContext *ctx, JSValue specifier = argv[3]; JSModuleDef *m; const char *basename = NULL, *filename; - JSValue ret, err, ns; + JSValue ret, err; if (!JS_IsString(basename_val)) { JS_ThrowTypeError(ctx, "no function filename for import()"); @@ -26880,39 +27041,12 @@ static JSValue js_dynamic_import_job(JSContext *ctx, if (!filename) goto exception; - m = JS_RunModule(ctx, basename, filename); + JS_LoadModuleInternal(ctx, basename, filename, + resolving_funcs); JS_FreeCString(ctx, filename); - if (!m) - goto exception; - - /* return the module namespace */ - ns = JS_GetModuleNamespace(ctx, m); - if (JS_IsException(ns)) - goto exception; - - if (!JS_IsUndefined(m->promise)) { - JSValue args[] = {argv[0], argv[1], ns}; - JSValue funcs[2]; - funcs[0] = JS_NewCFunctionData(ctx, js_dynamic_import_resolve, 0, 0, 3, args); - funcs[1] = JS_NewCFunctionData(ctx, js_dynamic_import_reject, 0, 0, 3, args); - JS_FreeValue(ctx, js_promise_then(ctx, m->promise, 2, funcs)); - - JS_FreeValue(ctx, funcs[0]); - JS_FreeValue(ctx, funcs[1]); - JS_FreeValue(ctx, ns); - JS_FreeCString(ctx, basename); - - return JS_UNDEFINED; - } - - ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, - 1, &ns); - JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */ - JS_FreeValue(ctx, ns); JS_FreeCString(ctx, basename); return JS_UNDEFINED; exception: - err = JS_GetException(ctx); ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, &err); @@ -26948,6 +27082,8 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValue specifier) args[2] = basename_val; args[3] = specifier; + /* cannot run JS_LoadModuleInternal synchronously because it would + cause an unexpected recursion in js_evaluate_module() */ JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args); JS_FreeValue(ctx, basename_val); @@ -26956,106 +27092,397 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValue specifier) return promise; } -static JSValue js_async_function_call2(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv, int magic, JSValue *func_data) +static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m) { - return js_async_function_call(ctx, func_data[0], this_val, argc, argv, magic); + m->status = JS_MODULE_STATUS_EVALUATED; + if (!JS_IsUndefined(m->promise)) { + JSValue value, ret_val; + assert(m->cycle_root == m); + value = JS_UNDEFINED; + ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED, + 1, (JSValueConst *)&value); + JS_FreeValue(ctx, ret_val); + } } -/* Run the function of the module and of all its requested - modules. */ -static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m) +typedef struct { + JSModuleDef **tab; + int count; + int size; +} ExecModuleList; + +/* XXX: slow. Could use a linked list instead of ExecModuleList */ +static BOOL find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m) +{ + int i; + for(i = 0; i < exec_list->count; i++) { + if (exec_list->tab[i] == m) + return TRUE; + } + return FALSE; +} + +static int gather_available_ancestors(JSContext *ctx, JSModuleDef *module, + ExecModuleList *exec_list) +{ + int i; + + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + return -1; + } + for(i = 0; i < module->async_parent_modules_count; i++) { + JSModuleDef *m = module->async_parent_modules[i]; + if (!find_in_exec_module_list(exec_list, m) && + !m->cycle_root->eval_has_exception) { + assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC); + assert(!m->eval_has_exception); + assert(m->async_evaluation); + assert(m->pending_async_dependencies > 0); + m->pending_async_dependencies--; + if (m->pending_async_dependencies == 0) { + if (js_resize_array(ctx, (void **)&exec_list->tab, sizeof(exec_list->tab[0]), &exec_list->size, exec_list->count + 1)) { + return -1; + } + exec_list->tab[exec_list->count++] = m; + if (!m->has_tla) { + if (gather_available_ancestors(ctx, m, exec_list)) + return -1; + } + } + } + } + return 0; +} + +static int exec_module_list_cmp(const void *p1, const void *p2, void *opaque) +{ + JSModuleDef *m1 = *(JSModuleDef **)p1; + JSModuleDef *m2 = *(JSModuleDef **)p2; + return (m1->async_evaluation_timestamp > m2->async_evaluation_timestamp) - + (m1->async_evaluation_timestamp < m2->async_evaluation_timestamp); +} + +static int js_execute_async_module(JSContext *ctx, JSModuleDef *m); +static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m, + JSValue *pvalue); + +static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) +{ + JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]); + JSValueConst error = argv[0]; + int i; + + if (js_check_stack_overflow(ctx->rt, 0)) + return JS_ThrowStackOverflow(ctx); + + if (module->status == JS_MODULE_STATUS_EVALUATED) { + assert(module->eval_has_exception); + return JS_UNDEFINED; + } + + assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC); + assert(!module->eval_has_exception); + assert(module->async_evaluation); + + module->eval_has_exception = TRUE; + module->eval_exception = JS_DupValue(ctx, error); + module->status = JS_MODULE_STATUS_EVALUATED; + + for(i = 0; i < module->async_parent_modules_count; i++) { + JSModuleDef *m = module->async_parent_modules[i]; + JSValue m_obj = JS_NewModuleValue(ctx, m); + js_async_module_execution_rejected(ctx, JS_UNDEFINED, 1, &error, 0, + &m_obj); + JS_FreeValue(ctx, m_obj); + } + + if (!JS_IsUndefined(module->promise)) { + JSValue ret_val; + assert(module->cycle_root == module); + ret_val = JS_Call(ctx, module->resolving_funcs[1], JS_UNDEFINED, + 1, &error); + JS_FreeValue(ctx, ret_val); + } + return JS_UNDEFINED; +} + +static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) +{ + JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]); + ExecModuleList exec_list_s, *exec_list = &exec_list_s; + int i; + + if (module->status == JS_MODULE_STATUS_EVALUATED) { + assert(module->eval_has_exception); + return JS_UNDEFINED; + } + assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC); + assert(!module->eval_has_exception); + assert(module->async_evaluation); + module->async_evaluation = FALSE; + js_set_module_evaluated(ctx, module); + + exec_list->tab = NULL; + exec_list->count = 0; + exec_list->size = 0; + + if (gather_available_ancestors(ctx, module, exec_list) < 0) { + js_free(ctx, exec_list->tab); + return JS_EXCEPTION; + } + + /* sort by increasing async_evaluation timestamp */ + rqsort(exec_list->tab, exec_list->count, sizeof(exec_list->tab[0]), + exec_module_list_cmp, NULL); + + for(i = 0; i < exec_list->count; i++) { + JSModuleDef *m = exec_list->tab[i]; + if (m->status == JS_MODULE_STATUS_EVALUATED) { + assert(m->eval_has_exception); + } else if (m->has_tla) { + js_execute_async_module(ctx, m); + } else { + JSValue error; + if (js_execute_sync_module(ctx, m, &error) < 0) { + JSValue m_obj = JS_NewModuleValue(ctx, m); + js_async_module_execution_rejected(ctx, JS_UNDEFINED, + 1, (JSValueConst *)&error, 0, + &m_obj); + JS_FreeValue(ctx, m_obj); + JS_FreeValue(ctx, error); + } else { + js_set_module_evaluated(ctx, m); + } + } + } + js_free(ctx, exec_list->tab); + return JS_UNDEFINED; +} + +static int js_execute_async_module(JSContext *ctx, JSModuleDef *m) +{ + JSValue promise, m_obj; + JSValue resolve_funcs[2], ret_val; + promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0); + if (JS_IsException(promise)) + return -1; + m_obj = JS_NewModuleValue(ctx, m); + resolve_funcs[0] = JS_NewCFunctionData(ctx, js_async_module_execution_fulfilled, 0, 0, 1, (JSValueConst *)&m_obj); + resolve_funcs[1] = JS_NewCFunctionData(ctx, js_async_module_execution_rejected, 0, 0, 1, (JSValueConst *)&m_obj); + ret_val = js_promise_then(ctx, promise, 2, (JSValueConst *)resolve_funcs); + JS_FreeValue(ctx, ret_val); + JS_FreeValue(ctx, m_obj); + JS_FreeValue(ctx, resolve_funcs[0]); + JS_FreeValue(ctx, resolve_funcs[1]); + JS_FreeValue(ctx, promise); + return 0; +} + +/* return < 0 in case of exception. *pvalue contains the exception. */ +static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m, + JSValue *pvalue) +{ + if (m->init_func) { + /* C module init : no asynchronous execution */ + if (m->init_func(ctx, m) < 0) + goto fail; + } else { + JSValue promise; + JSPromiseStateEnum state; + + promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0); + if (JS_IsException(promise)) + goto fail; + state = JS_PromiseState(ctx, promise); + if (state == JS_PROMISE_FULFILLED) { + JS_FreeValue(ctx, promise); + } else if (state == JS_PROMISE_REJECTED) { + *pvalue = JS_PromiseResult(ctx, promise); + JS_FreeValue(ctx, promise); + return -1; + } else { + JS_FreeValue(ctx, promise); + JS_ThrowTypeError(ctx, "promise is pending"); + fail: + *pvalue = JS_GetException(ctx); + return -1; + } + } + *pvalue = JS_UNDEFINED; + return 0; +} + +/* spec: InnerModuleEvaluation. Return (index, JS_UNDEFINED) or (-1, + exception) */ +static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m, + int index, JSModuleDef **pstack_top, + JSValue *pvalue) { JSModuleDef *m1; int i; - JSValue ret_val; - if (m->eval_mark) - return JS_UNDEFINED; /* avoid cycles */ - - if (m->evaluated) { - /* if the module was already evaluated, rethrow the exception - it raised */ - if (m->eval_has_exception) { - return JS_Throw(ctx, js_dup(m->eval_exception)); - } else { - return js_dup(m->promise); - } + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + *pvalue = JS_GetException(ctx); + return -1; } - m->eval_mark = TRUE; +#ifdef DUMP_MODULE_RESOLVE + { + char buf1[ATOM_GET_STR_BUF_SIZE]; + printf("js_inner_module_evaluation '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); + } +#endif - JSValue promises = JS_NewArray(ctx); - if (JS_IsException(promises)) - return JS_EXCEPTION; + if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED) { + if (m->eval_has_exception) { + *pvalue = JS_DupValue(ctx, m->eval_exception); + return -1; + } else { + *pvalue = JS_UNDEFINED; + return index; + } + } + if (m->status == JS_MODULE_STATUS_EVALUATING) { + *pvalue = JS_UNDEFINED; + return index; + } + assert(m->status == JS_MODULE_STATUS_LINKED); + + m->status = JS_MODULE_STATUS_EVALUATING; + m->dfs_index = index; + m->dfs_ancestor_index = index; + m->pending_async_dependencies = 0; + index++; + /* push 'm' on stack */ + m->stack_prev = *pstack_top; + *pstack_top = m; - BOOL async = FALSE; - JSValue promise = JS_UNDEFINED; for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; m1 = rme->module; - if (!m1->eval_mark) { - ret_val = js_evaluate_module(ctx, m1); - if (JS_IsException(ret_val)) { - m->eval_mark = FALSE; - js_free_modules(ctx, JS_FREE_MODULE_NOT_EVALUATED); - goto clean; + index = js_inner_module_evaluation(ctx, m1, index, pstack_top, pvalue); + if (index < 0) + return -1; + assert(m1->status == JS_MODULE_STATUS_EVALUATING || + m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m1->status == JS_MODULE_STATUS_EVALUATED); + if (m1->status == JS_MODULE_STATUS_EVALUATING) { + m->dfs_ancestor_index = min_int(m->dfs_ancestor_index, + m1->dfs_ancestor_index); + } else { + m1 = m1->cycle_root; + assert(m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m1->status == JS_MODULE_STATUS_EVALUATED); + if (m1->eval_has_exception) { + *pvalue = JS_DupValue(ctx, m1->eval_exception); + return -1; } - if (!JS_IsUndefined(ret_val)) { - js_array_push(ctx, promises, 1, &ret_val, 0); - JS_FreeValue(ctx, ret_val); - async = TRUE; + } + if (m1->async_evaluation) { + m->pending_async_dependencies++; + if (js_resize_array(ctx, (void **)&m1->async_parent_modules, sizeof(m1->async_parent_modules[0]), &m1->async_parent_modules_size, m1->async_parent_modules_count + 1)) { + *pvalue = JS_GetException(ctx); + return -1; } + m1->async_parent_modules[m1->async_parent_modules_count++] = m; } } - promise = js_promise_all(ctx, ctx->promise_ctor, 1, &promises, 0); - if (JS_IsException(promise)) { - JS_FreeValue(ctx, promises); - return JS_EXCEPTION; - } - - if (m->init_func) { - /* C module init */ - if (m->init_func(ctx, m) < 0) - ret_val = JS_EXCEPTION; - else - ret_val = JS_UNDEFINED; - } else if (!async) { - ret_val = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0); - JS_FreeValue(ctx, m->func_obj); - m->func_obj = JS_UNDEFINED; - JSPromiseData *s = JS_GetOpaque(ret_val, JS_CLASS_PROMISE); - if (s->promise_state != JS_PROMISE_PENDING) { - JSValue ret_val2 = ret_val; - if (s->promise_state == JS_PROMISE_REJECTED) - ret_val = JS_Throw(ctx, js_dup(s->promise_result)); - else - ret_val = js_dup(s->promise_result); - JS_FreeValue(ctx, ret_val2); - } + if (m->pending_async_dependencies > 0) { + assert(!m->async_evaluation); + m->async_evaluation = TRUE; + m->async_evaluation_timestamp = + ctx->rt->module_async_evaluation_next_timestamp++; + } else if (m->has_tla) { + assert(!m->async_evaluation); + m->async_evaluation = TRUE; + m->async_evaluation_timestamp = + ctx->rt->module_async_evaluation_next_timestamp++; + js_execute_async_module(ctx, m); } else { - JSValue funcs[2]; - funcs[0] = JS_NewCFunctionData(ctx, js_async_function_call2, 0, 0, 1, &m->func_obj); - funcs[1] = JS_UNDEFINED; - ret_val = js_promise_then(ctx, promise, 2, funcs); - JS_FreeValue(ctx, funcs[0]); - JS_FreeValue(ctx, m->func_obj); - m->func_obj = JS_UNDEFINED; + if (js_execute_sync_module(ctx, m, pvalue) < 0) + return -1; } - if (JS_IsException(ret_val)) { - /* save the thrown exception value */ - m->eval_has_exception = TRUE; - m->eval_exception = js_dup(ctx->rt->current_exception); - } else if (!JS_IsUndefined(ret_val)) { - m->promise = js_dup(ret_val); + + assert(m->dfs_ancestor_index <= m->dfs_index); + if (m->dfs_index == m->dfs_ancestor_index) { + for(;;) { + /* pop m1 from stack */ + m1 = *pstack_top; + *pstack_top = m1->stack_prev; + if (!m1->async_evaluation) { + m1->status = JS_MODULE_STATUS_EVALUATED; + } else { + m1->status = JS_MODULE_STATUS_EVALUATING_ASYNC; + } + /* spec bug: cycle_root must be assigned before the test */ + m1->cycle_root = m; + if (m1 == m) + break; + } } - m->eval_mark = FALSE; - m->evaluated = TRUE; -clean: - JS_FreeValue(ctx, promises); - JS_FreeValue(ctx, promise); - return ret_val; + *pvalue = JS_UNDEFINED; + return index; +} + +/* Run the function of the module and of all its requested + modules. Return a promise or an exception. */ +static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m) +{ + JSModuleDef *m1, *stack_top; + JSValue ret_val, result; + + assert(m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED) { + m = m->cycle_root; + } + /* a promise may be created only on the cycle_root of a cycle */ + if (!JS_IsUndefined(m->promise)) + return JS_DupValue(ctx, m->promise); + m->promise = JS_NewPromiseCapability(ctx, m->resolving_funcs); + if (JS_IsException(m->promise)) + return JS_EXCEPTION; + + stack_top = NULL; + if (js_inner_module_evaluation(ctx, m, 0, &stack_top, &result) < 0) { + while (stack_top != NULL) { + m1 = stack_top; + assert(m1->status == JS_MODULE_STATUS_EVALUATING); + m1->status = JS_MODULE_STATUS_EVALUATED; + m1->eval_has_exception = TRUE; + m1->eval_exception = JS_DupValue(ctx, result); + m1->cycle_root = m; /* spec bug: should be present */ + stack_top = m1->stack_prev; + } + JS_FreeValue(ctx, result); + assert(m->status == JS_MODULE_STATUS_EVALUATED); + assert(m->eval_has_exception); + ret_val = JS_Call(ctx, m->resolving_funcs[1], JS_UNDEFINED, + 1, (JSValueConst *)&m->eval_exception); + JS_FreeValue(ctx, ret_val); + } else { + assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + assert(!m->eval_has_exception); + if (!m->async_evaluation) { + JSValue value; + assert(m->status == JS_MODULE_STATUS_EVALUATED); + value = JS_UNDEFINED; + ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED, + 1, (JSValueConst *)&value); + JS_FreeValue(ctx, ret_val); + } + assert(stack_top == NULL); + } + return JS_DupValue(ctx, m->promise); } static __exception JSAtom js_parse_from_clause(JSParseState *s) @@ -32301,10 +32728,22 @@ static __exception int js_parse_program(JSParseState *s) if (!s->is_module) { /* return the value of the hidden variable eval_ret_idx */ - emit_op(s, OP_get_loc); - emit_u16(s, fd->eval_ret_idx); + if (fd->func_kind == JS_FUNC_ASYNC) { + /* wrap the return value in an object so that promises can + be safely returned */ + emit_op(s, OP_object); + emit_op(s, OP_dup); - emit_op(s, OP_return); + emit_op(s, OP_get_loc); + emit_u16(s, fd->eval_ret_idx); + + emit_op(s, OP_put_field); + emit_atom(s, JS_ATOM_value); + } else { + emit_op(s, OP_get_loc); + emit_u16(s, fd->eval_ret_idx); + } + emit_return(s, TRUE); } else { emit_return(s, FALSE); } @@ -32353,7 +32792,6 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj, ret_val = js_evaluate_module(ctx, m); if (JS_IsException(ret_val)) { fail: - js_free_modules(ctx, JS_FREE_MODULE_NOT_EVALUATED); return JS_EXCEPTION; } } else { @@ -32418,10 +32856,6 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValue this_obj, fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename, 1, 1); if (!fd) goto fail1; - if (m != NULL) { - fd->in_function_body = TRUE; - fd->func_kind = JS_FUNC_ASYNC; - } s->cur_func = fd; fd->eval_type = eval_type; fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT); @@ -32444,6 +32878,10 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValue this_obj, goto fail; } fd->module = m; + if (m != NULL || (flags & JS_EVAL_FLAG_ASYNC)) { + fd->in_function_body = TRUE; + fd->func_kind = JS_FUNC_ASYNC; + } s->is_module = (m != NULL); s->allow_html_comments = !s->is_module; @@ -32458,6 +32896,9 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValue this_obj, goto fail1; } + if (m != NULL) + m->has_tla = fd->has_await; + /* create the function object and all the enclosed functions */ fun_obj = js_create_function(ctx, fd); if (JS_IsException(fun_obj)) @@ -32467,7 +32908,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValue this_obj, m->func_obj = fun_obj; if (js_resolve_module(ctx, m) < 0) goto fail1; - fun_obj = js_dup(JS_MKPTR(JS_TAG_MODULE, m)); + fun_obj = JS_NewModuleValue(ctx, m); } if (flags & JS_EVAL_FLAG_COMPILE_ONLY) { ret_val = fun_obj; @@ -33163,6 +33604,8 @@ static int JS_WriteModule(BCWriterState *s, JSValue obj) bc_put_leb128(s, mi->req_module_idx); } + bc_put_u8(s, m->has_tla); + if (JS_WriteObjectRec(s, m->func_obj)) goto fail; return 0; @@ -34203,6 +34646,7 @@ static JSValue JS_ReadModule(BCReaderState *s) obj = js_dup(JS_MKPTR(JS_TAG_MODULE, m)); if (bc_get_leb128_int(s, &m->req_module_entries_count)) goto fail; + obj = JS_NewModuleValue(ctx, m); if (m->req_module_entries_count != 0) { m->req_module_entries_size = m->req_module_entries_count; m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size); @@ -34273,6 +34717,10 @@ static JSValue JS_ReadModule(BCReaderState *s) } } + if (bc_get_u8(s, &v8)) + goto fail; + m->has_tla = (v8 != 0); + m->func_obj = JS_ReadObjectRec(s); if (JS_IsException(m->func_obj)) goto fail; @@ -45680,6 +46128,14 @@ static const JSCFunctionListEntry js_generator_proto_funcs[] = { /* Promise */ +typedef struct JSPromiseData { + JSPromiseStateEnum promise_state; + /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */ + struct list_head promise_reactions[2]; + BOOL is_handled; /* Note: only useful to debug */ + JSValue promise_result; +} JSPromiseData; + typedef struct JSPromiseFunctionDataResolved { int ref_count; BOOL already_resolved; @@ -45696,11 +46152,11 @@ typedef struct JSPromiseReactionData { JSValue handler; } JSPromiseReactionData; -JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise) + JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise) { JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE); if (!s) - return JS_INVALID_PROMISE_STATE; + return -1; return s->promise_state; } @@ -45709,7 +46165,7 @@ JSValue JS_PromiseResult(JSContext *ctx, JSValue promise) JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE); if (!s) return JS_UNDEFINED; - return js_dup(s->promise_result); + return JS_DupValue(ctx, s->promise_result); } static int js_create_resolving_functions(JSContext *ctx, JSValue *args, diff --git a/quickjs.h b/quickjs.h index 5420b3d..0d7d5cb 100644 --- a/quickjs.h +++ b/quickjs.h @@ -275,6 +275,9 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) /* don't include the stack frames before this eval in the Error() backtraces */ #define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6) +/* allow top-level await in normal script. JS_Eval() returns a + promise. Only allowed with JS_EVAL_TYPE_GLOBAL */ +#define JS_EVAL_FLAG_ASYNC (1 << 7) typedef JSValue JSCFunction(JSContext *ctx, JSValue this_val, int argc, JSValue *argv); typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic); @@ -782,7 +785,15 @@ typedef struct { } JSSharedArrayBufferFunctions; JS_EXTERN void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, const JSSharedArrayBufferFunctions *sf); +typedef enum JSPromiseStateEnum { + JS_PROMISE_PENDING, + JS_PROMISE_FULFILLED, + JS_PROMISE_REJECTED, +} JSPromiseStateEnum; + JS_EXTERN JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); +JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise); +JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValue promise); JS_EXTERN JSValue JS_NewSymbol(JSContext *ctx, const char *description, JS_BOOL is_global); @@ -854,8 +865,8 @@ JS_EXTERN int JS_ResolveModule(JSContext *ctx, JSValue obj); /* only exported for os.Worker() */ JS_EXTERN JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels); /* only exported for os.Worker() */ -JS_EXTERN JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, - const char *filename); +JS_EXTERN JSValue JS_LoadModule(JSContext *ctx, const char *basename, + const char *filename); /* C function definition */ typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ @@ -994,21 +1005,6 @@ JS_EXTERN int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *exp JS_EXTERN int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, const JSCFunctionListEntry *tab, int len); -/* Promise */ - -#define JS_INVALID_PROMISE_STATE (-1) - -typedef enum JSPromiseStateEnum { - JS_PROMISE_PENDING, - JS_PROMISE_FULFILLED, - JS_PROMISE_REJECTED, -} JSPromiseStateEnum; - -/* Returns JSPromiseReactionEnum for the promise or JS_INVALID_PROMISE_STATE if the value is not a promise. */ -JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise); -/* Return the result of the promise if the promise's state is in the FULFILLED or REJECTED state. Otherwise returns JS_UNDEFINED. */ -JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValue promise); - /* Version */ #define QJS_VERSION_MAJOR 0 diff --git a/repl.js b/repl.js index fcb38c7..3074819 100644 --- a/repl.js +++ b/repl.js @@ -129,6 +129,7 @@ import * as os from "os"; var plen = 0; var ps1 = "qjs > "; var ps2 = " ... "; + var eval_start_time; var eval_time = 0; var mexpr = ""; var level = 0; @@ -838,10 +839,8 @@ import * as os from "os"; prompt += ps2; } else { if (show_time) { - var t = Math.round(eval_time) + " "; - eval_time = 0; - t = dupstr("0", 5 - t.length) + t; - prompt += t.substring(0, t.length - 4) + "." + t.substring(t.length - 4); + var t = eval_time / 1000; + prompt += t.toFixed(6) + " "; } plen = prompt.length; prompt += ps1; @@ -1507,34 +1506,6 @@ import * as os from "os"; "quit": () => { exit(0); }, }, null); - function eval_and_print(expr) { - var result; - - try { - if (use_strict) - expr = '"use strict"; void 0;' + expr; - var now = Date.now(); - /* eval as a script */ - result = std.evalScript(expr, { backtrace_barrier: true }); - eval_time = Date.now() - now; - print(result); - /* set the last result */ - g._ = result; - } catch (error) { - std.puts(colors[styles.error]); - if (error instanceof Error) { - console.log(error); - if (error.stack) { - std.puts(error.stack); - } - } else { - std.puts("Throw: "); - console.log(error); - } - std.puts(colors.none); - } - } - function cmd_start() { std.puts('QuickJS-ng - Type ".help" for help\n'); cmd_readline_start(); @@ -1545,33 +1516,88 @@ import * as os from "os"; } function readline_handle_cmd(expr) { - handle_cmd(expr); - cmd_readline_start(); + if (!handle_cmd(expr)) { + cmd_readline_start(); + } } + /* return true if async termination */ function handle_cmd(expr) { if (!expr) - return; + return false; if (mexpr) { expr = mexpr + '\n' + expr; } else { if (handle_directive(expr)) - return; + return false; } var colorstate = colorize_js(expr); pstate = colorstate[0]; level = colorstate[1]; if (pstate) { mexpr = expr; - return; + return false; } mexpr = ""; - eval_and_print(expr); + eval_and_print_start(expr, true); + + return true; + } + + function eval_and_print_start(expr, is_async) { + var result; + + try { + if (use_strict) + expr = '"use strict"; void 0;' + expr; + eval_start_time = os.now(); + /* eval as a script */ + result = std.evalScript(expr, { backtrace_barrier: true, async: is_async }); + if (is_async) { + /* result is a promise */ + result.then(print_eval_result, print_eval_error); + } else { + print_eval_result({ value: result }); + } + } catch (error) { + print_eval_error(error); + } + } + + function print_eval_result(result) { + result = result.value; + eval_time = os.now() - eval_start_time; + print(result); + /* set the last result */ + g._ = result; + + handle_cmd_end(); + } + + function print_eval_error(error) { + std.puts(colors[styles.error]); + if (error instanceof Error) { + console.log(error); + if (error.stack) { + std.puts(error.stack); + } + } else { + std.puts("Throw: "); + console.log(error); + } + std.puts(colors.none); + + handle_cmd_end(); + } + + function handle_cmd_end() { level = 0; /* run the garbage collector after each command */ std.gc(); + + cmd_readline_start(); } function colorize_js(str) { diff --git a/run-test262.c b/run-test262.c index be4ed4d..2e60bbc 100644 --- a/run-test262.c +++ b/run-test262.c @@ -1198,7 +1198,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len, { JSValue res_val, exception_val; int ret, error_line, pos, pos_line; - BOOL is_error, has_error_line; + BOOL is_error, has_error_line, ret_promise; const char *error_name; pos = skip_comments(buf, 1, &pos_line); @@ -1207,12 +1207,19 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len, exception_val = JS_UNDEFINED; error_name = NULL; + /* a module evaluation returns a promise */ + ret_promise = ((eval_flags & JS_EVAL_TYPE_MODULE) != 0); async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */ res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); - if (is_async && !JS_IsException(res_val)) { - JS_FreeValue(ctx, res_val); + if ((is_async || ret_promise) && !JS_IsException(res_val)) { + JSValue promise = JS_UNDEFINED; + if (ret_promise) { + promise = res_val; + } else { + JS_FreeValue(ctx, res_val); + } for(;;) { JSContext *ctx1; ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); @@ -1220,37 +1227,26 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len, res_val = JS_EXCEPTION; break; } else if (ret == 0) { - /* test if the test called $DONE() once */ - if (async_done != 1) { - res_val = JS_ThrowTypeError(ctx, "$DONE() not called"); + if (is_async) { + /* test if the test called $DONE() once */ + if (async_done != 1) { + res_val = JS_ThrowTypeError(ctx, "$DONE() not called"); + } else { + res_val = JS_UNDEFINED; + } } else { - res_val = JS_UNDEFINED; + /* check that the returned promise is fulfilled */ + JSPromiseStateEnum state = JS_PromiseState(ctx, promise); + if (state == JS_PROMISE_FULFILLED) + res_val = JS_UNDEFINED; + else if (state == JS_PROMISE_REJECTED) + res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise)); + else + res_val = JS_ThrowTypeError(ctx, "promise is pending"); } break; } } - } else if ((eval_flags & JS_EVAL_TYPE_MODULE) && - !JS_IsUndefined(res_val) && - !JS_IsException(res_val)) { - JSValue promise = res_val; - for(;;) { - JSContext *ctx1; - ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); - if (ret < 0) { - res_val = JS_EXCEPTION; - break; - } - if (ret == 0) { - JSPromiseStateEnum s = JS_PromiseState(ctx, promise); - if (s == JS_PROMISE_FULFILLED) - res_val = JS_UNDEFINED; - else if (s == JS_PROMISE_REJECTED) - res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise)); - else - res_val = JS_EXCEPTION; - break; - } - } JS_FreeValue(ctx, promise); } @@ -1887,17 +1883,32 @@ int run_test262_harness_test(const char *filename, BOOL is_module) js_std_dump_error(ctx); ret_code = 1; } else { - JS_FreeValue(ctx, res_val); + JSValue promise = JS_UNDEFINED; + if (is_module) { + promise = res_val; + } else { + JS_FreeValue(ctx, res_val); + } for(;;) { JSContext *ctx1; ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); if (ret < 0) { - js_std_dump_error(ctx1); - ret_code = 1; + js_std_dump_error(ctx1); + ret_code = 1; } else if (ret == 0) { - break; + break; } - } + } + /* dump the error if the module returned an error. */ + if (is_module) { + JSPromiseStateEnum state = JS_PromiseState(ctx, promise); + if (state == JS_PROMISE_REJECTED) { + JS_Throw(ctx, JS_PromiseResult(ctx, promise)); + js_std_dump_error(ctx); + ret_code = 1; + } + } + JS_FreeValue(ctx, promise); } free(buf); #ifdef CONFIG_AGENT