mirror of
				https://github.com/bellard/quickjs.git
				synced 2025-05-29 01:49:18 +08:00 
			
		
		
		
	top-level-await support - follow the spec in the implementation of the module linking and evaluation to avoid errors with cycling module dependencies
This commit is contained in:
		
							parent
							
								
									9b587c461b
								
							
						
					
					
						commit
						6e4931c4ad
					
				@ -3274,6 +3274,7 @@ static void *worker_func(void *opaque)
 | 
				
			|||||||
    JSRuntime *rt;
 | 
					    JSRuntime *rt;
 | 
				
			||||||
    JSThreadState *ts;
 | 
					    JSThreadState *ts;
 | 
				
			||||||
    JSContext *ctx;
 | 
					    JSContext *ctx;
 | 
				
			||||||
 | 
					    JSValue promise;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    rt = JS_NewRuntime();
 | 
					    rt = JS_NewRuntime();
 | 
				
			||||||
    if (rt == NULL) {
 | 
					    if (rt == NULL) {
 | 
				
			||||||
@ -3300,8 +3301,11 @@ static void *worker_func(void *opaque)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    js_std_add_helpers(ctx, -1, NULL);
 | 
					    js_std_add_helpers(ctx, -1, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!JS_RunModule(ctx, args->basename, args->filename))
 | 
					    promise = JS_LoadModule(ctx, args->basename, args->filename);
 | 
				
			||||||
 | 
					    if (JS_IsException(promise))
 | 
				
			||||||
        js_std_dump_error(ctx);
 | 
					        js_std_dump_error(ctx);
 | 
				
			||||||
 | 
					    /* XXX: check */
 | 
				
			||||||
 | 
					    JS_FreeValue(ctx, promise);
 | 
				
			||||||
    free(args->filename);
 | 
					    free(args->filename);
 | 
				
			||||||
    free(args->basename);
 | 
					    free(args->basename);
 | 
				
			||||||
    free(args);
 | 
					    free(args);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										714
									
								
								quickjs.c
									
									
									
									
									
								
							
							
						
						
									
										714
									
								
								quickjs.c
									
									
									
									
									
								
							@ -283,6 +283,8 @@ struct JSRuntime {
 | 
				
			|||||||
    JSModuleNormalizeFunc *module_normalize_func;
 | 
					    JSModuleNormalizeFunc *module_normalize_func;
 | 
				
			||||||
    JSModuleLoaderFunc *module_loader_func;
 | 
					    JSModuleLoaderFunc *module_loader_func;
 | 
				
			||||||
    void *module_loader_opaque;
 | 
					    void *module_loader_opaque;
 | 
				
			||||||
 | 
					    /* timestamp for internal use in module evaluation */
 | 
				
			||||||
 | 
					    int64_t module_async_evaluation_next_timestamp;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    BOOL can_block : 8; /* TRUE if Atomics.wait can block */
 | 
					    BOOL can_block : 8; /* TRUE if Atomics.wait can block */
 | 
				
			||||||
    /* used to allocate, free and clone SharedArrayBuffers */
 | 
					    /* used to allocate, free and clone SharedArrayBuffers */
 | 
				
			||||||
@ -765,6 +767,15 @@ typedef struct JSImportEntry {
 | 
				
			|||||||
    int req_module_idx; /* in req_module_entries */
 | 
					    int req_module_idx; /* in req_module_entries */
 | 
				
			||||||
} JSImportEntry;
 | 
					} 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 {
 | 
					struct JSModuleDef {
 | 
				
			||||||
    JSRefCountHeader header; /* must come first, 32-bit */
 | 
					    JSRefCountHeader header; /* must come first, 32-bit */
 | 
				
			||||||
    JSAtom module_name;
 | 
					    JSAtom module_name;
 | 
				
			||||||
@ -789,11 +800,24 @@ struct JSModuleDef {
 | 
				
			|||||||
    JSValue module_ns;
 | 
					    JSValue module_ns;
 | 
				
			||||||
    JSValue func_obj; /* only used for JS modules */
 | 
					    JSValue func_obj; /* only used for JS modules */
 | 
				
			||||||
    JSModuleInitFunc *init_func; /* only used for C modules */
 | 
					    JSModuleInitFunc *init_func; /* only used for C modules */
 | 
				
			||||||
 | 
					    BOOL has_tla : 8; /* true if func_obj contains await */
 | 
				
			||||||
    BOOL resolved : 8;
 | 
					    BOOL resolved : 8;
 | 
				
			||||||
    BOOL func_created : 8;
 | 
					    BOOL func_created : 8;
 | 
				
			||||||
    BOOL instantiated : 8;
 | 
					    JSModuleStatus status : 8;
 | 
				
			||||||
    BOOL evaluated : 8;
 | 
					    /* temp use during js_module_link() & js_module_evaluate() */
 | 
				
			||||||
    BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */
 | 
					    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
 | 
					    /* true if evaluation yielded an exception. It is saved in
 | 
				
			||||||
       eval_exception */
 | 
					       eval_exception */
 | 
				
			||||||
    BOOL eval_has_exception : 8; 
 | 
					    BOOL eval_has_exception : 8; 
 | 
				
			||||||
@ -1198,6 +1222,8 @@ static __exception int perform_promise_then(JSContext *ctx,
 | 
				
			|||||||
                                            JSValueConst *cap_resolving_funcs);
 | 
					                                            JSValueConst *cap_resolving_funcs);
 | 
				
			||||||
static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
 | 
					static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
 | 
				
			||||||
                                  int argc, JSValueConst *argv, int magic);
 | 
					                                  int argc, JSValueConst *argv, int magic);
 | 
				
			||||||
 | 
					static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
 | 
				
			||||||
 | 
					                               int argc, JSValueConst *argv);
 | 
				
			||||||
static int js_string_compare(JSContext *ctx,
 | 
					static int js_string_compare(JSContext *ctx,
 | 
				
			||||||
                             const JSString *p1, const JSString *p2);
 | 
					                             const JSString *p1, const JSString *p2);
 | 
				
			||||||
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
 | 
					static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
 | 
				
			||||||
@ -2192,7 +2218,6 @@ JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id)
 | 
				
			|||||||
typedef enum JSFreeModuleEnum {
 | 
					typedef enum JSFreeModuleEnum {
 | 
				
			||||||
    JS_FREE_MODULE_ALL,
 | 
					    JS_FREE_MODULE_ALL,
 | 
				
			||||||
    JS_FREE_MODULE_NOT_RESOLVED,
 | 
					    JS_FREE_MODULE_NOT_RESOLVED,
 | 
				
			||||||
    JS_FREE_MODULE_NOT_EVALUATED,
 | 
					 | 
				
			||||||
} JSFreeModuleEnum;
 | 
					} JSFreeModuleEnum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* XXX: would be more efficient with separate module lists */
 | 
					/* XXX: would be more efficient with separate module lists */
 | 
				
			||||||
@ -2202,8 +2227,7 @@ static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
 | 
				
			|||||||
    list_for_each_safe(el, el1, &ctx->loaded_modules) {
 | 
					    list_for_each_safe(el, el1, &ctx->loaded_modules) {
 | 
				
			||||||
        JSModuleDef *m = list_entry(el, JSModuleDef, link);
 | 
					        JSModuleDef *m = list_entry(el, JSModuleDef, link);
 | 
				
			||||||
        if (flag == JS_FREE_MODULE_ALL ||
 | 
					        if (flag == JS_FREE_MODULE_ALL ||
 | 
				
			||||||
            (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved) ||
 | 
					            (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) {
 | 
				
			||||||
            (flag == JS_FREE_MODULE_NOT_EVALUATED && !m->evaluated)) {
 | 
					 | 
				
			||||||
            js_free_module_def(ctx, m);
 | 
					            js_free_module_def(ctx, m);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -19716,6 +19740,7 @@ typedef struct JSFunctionDef {
 | 
				
			|||||||
    int source_len;
 | 
					    int source_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    JSModuleDef *module; /* != NULL when parsing a module */
 | 
					    JSModuleDef *module; /* != NULL when parsing a module */
 | 
				
			||||||
 | 
					    BOOL has_await; /* TRUE if await is used (used in module eval) */
 | 
				
			||||||
} JSFunctionDef;
 | 
					} JSFunctionDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct JSToken {
 | 
					typedef struct JSToken {
 | 
				
			||||||
@ -24774,6 +24799,7 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
 | 
				
			|||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
        if (js_parse_unary(s, PF_POW_FORBIDDEN))
 | 
					        if (js_parse_unary(s, PF_POW_FORBIDDEN))
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
 | 
					        s->cur_func->has_await = TRUE;
 | 
				
			||||||
        emit_op(s, OP_await);
 | 
					        emit_op(s, OP_await);
 | 
				
			||||||
        parse_flags = 0;
 | 
					        parse_flags = 0;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
@ -26173,6 +26199,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
 | 
				
			|||||||
                is_async = TRUE;
 | 
					                is_async = TRUE;
 | 
				
			||||||
                if (next_token(s))
 | 
					                if (next_token(s))
 | 
				
			||||||
                    goto fail;
 | 
					                    goto fail;
 | 
				
			||||||
 | 
					                s->cur_func->has_await = TRUE;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (js_parse_expect(s, '('))
 | 
					            if (js_parse_expect(s, '('))
 | 
				
			||||||
                goto fail;
 | 
					                goto fail;
 | 
				
			||||||
@ -26703,6 +26730,9 @@ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
 | 
				
			|||||||
    m->func_obj = JS_UNDEFINED;
 | 
					    m->func_obj = JS_UNDEFINED;
 | 
				
			||||||
    m->eval_exception = JS_UNDEFINED;
 | 
					    m->eval_exception = JS_UNDEFINED;
 | 
				
			||||||
    m->meta_obj = 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);
 | 
					    list_add_tail(&m->link, &ctx->loaded_modules);
 | 
				
			||||||
    return m;
 | 
					    return m;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -26724,6 +26754,9 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
 | 
				
			|||||||
    JS_MarkValue(rt, m->func_obj, mark_func);
 | 
					    JS_MarkValue(rt, m->func_obj, mark_func);
 | 
				
			||||||
    JS_MarkValue(rt, m->eval_exception, mark_func);
 | 
					    JS_MarkValue(rt, m->eval_exception, mark_func);
 | 
				
			||||||
    JS_MarkValue(rt, m->meta_obj, 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)
 | 
					static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
 | 
				
			||||||
@ -26754,11 +26787,15 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
 | 
				
			|||||||
        JS_FreeAtom(ctx, mi->import_name);
 | 
					        JS_FreeAtom(ctx, mi->import_name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    js_free(ctx, m->import_entries);
 | 
					    js_free(ctx, m->import_entries);
 | 
				
			||||||
 | 
					    js_free(ctx, m->async_parent_modules);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    JS_FreeValue(ctx, m->module_ns);
 | 
					    JS_FreeValue(ctx, m->module_ns);
 | 
				
			||||||
    JS_FreeValue(ctx, m->func_obj);
 | 
					    JS_FreeValue(ctx, m->func_obj);
 | 
				
			||||||
    JS_FreeValue(ctx, m->eval_exception);
 | 
					    JS_FreeValue(ctx, m->eval_exception);
 | 
				
			||||||
    JS_FreeValue(ctx, m->meta_obj);
 | 
					    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);
 | 
					    list_del(&m->link);
 | 
				
			||||||
    js_free(ctx, m);
 | 
					    js_free(ctx, m);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -27614,7 +27651,8 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
/* Prepare a module to be executed by resolving all the imported
 | 
					/* Prepare a module to be executed by resolving all the imported
 | 
				
			||||||
   variables. */
 | 
					   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;
 | 
					    int i;
 | 
				
			||||||
    JSImportEntry *mi;
 | 
					    JSImportEntry *mi;
 | 
				
			||||||
@ -27624,21 +27662,47 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
 | 
				
			|||||||
    BOOL is_c_module;
 | 
					    BOOL is_c_module;
 | 
				
			||||||
    JSValue ret_val;
 | 
					    JSValue ret_val;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (m->instantiated)
 | 
					    if (js_check_stack_overflow(ctx->rt, 0)) {
 | 
				
			||||||
        return 0;
 | 
					        JS_ThrowStackOverflow(ctx);
 | 
				
			||||||
    m->instantiated = TRUE;
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
#ifdef DUMP_MODULE_RESOLVE
 | 
					#ifdef DUMP_MODULE_RESOLVE
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        char buf1[ATOM_GET_STR_BUF_SIZE];
 | 
					        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
 | 
					#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++) {
 | 
					    for(i = 0; i < m->req_module_entries_count; i++) {
 | 
				
			||||||
        JSReqModuleEntry *rme = &m->req_module_entries[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;
 | 
					            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
 | 
					#ifdef DUMP_MODULE_RESOLVE
 | 
				
			||||||
@ -27764,14 +27828,59 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
 | 
				
			|||||||
        JS_FreeValue(ctx, ret_val);
 | 
					        JS_FreeValue(ctx, 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;
 | 
				
			||||||
 | 
					            m1->status = JS_MODULE_STATUS_LINKED;
 | 
				
			||||||
 | 
					            if (m1 == m)
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef DUMP_MODULE_RESOLVE
 | 
					#ifdef DUMP_MODULE_RESOLVE
 | 
				
			||||||
    printf("done instantiate\n");
 | 
					    printf("js_inner_module_linking done\n");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    return 0;
 | 
					    return index;
 | 
				
			||||||
 fail:
 | 
					 fail:
 | 
				
			||||||
    return -1;
 | 
					    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
 | 
					/* return JS_ATOM_NULL if the name cannot be found. Only works with
 | 
				
			||||||
   not striped bytecode functions. */
 | 
					   not striped bytecode functions. */
 | 
				
			||||||
JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
 | 
					JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
 | 
				
			||||||
@ -27841,29 +27950,110 @@ static JSValue js_import_meta(JSContext *ctx)
 | 
				
			|||||||
    return JS_GetImportMeta(ctx, m);
 | 
					    return JS_GetImportMeta(ctx, m);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* used by os.Worker() and import() */
 | 
					static JSValue JS_NewModuleValue(JSContext *ctx, JSModuleDef *m)
 | 
				
			||||||
JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
 | 
					 | 
				
			||||||
                          const char *filename)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    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_get_module_ns(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;
 | 
					    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);
 | 
					    m = js_host_resolve_imported_module(ctx, basename, filename);
 | 
				
			||||||
    if (!m)
 | 
					    if (!m)
 | 
				
			||||||
        return NULL;
 | 
					        goto fail;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (js_resolve_module(ctx, m) < 0) {
 | 
					    if (js_resolve_module(ctx, m) < 0) {
 | 
				
			||||||
        js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
 | 
					        js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
 | 
				
			||||||
        return NULL;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Evaluate the module code */
 | 
					    /* Evaluate the module code */
 | 
				
			||||||
    func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
 | 
					    func_obj = JS_NewModuleValue(ctx, m);
 | 
				
			||||||
    ret = JS_EvalFunction(ctx, func_obj);
 | 
					    evaluate_promise = JS_EvalFunction(ctx, func_obj);
 | 
				
			||||||
    if (JS_IsException(ret))
 | 
					    if (JS_IsException(evaluate_promise)) {
 | 
				
			||||||
        return NULL;
 | 
					    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);
 | 
					    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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    JSValue promise, resolving_funcs[2];
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    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,
 | 
					static JSValue js_dynamic_import_job(JSContext *ctx,
 | 
				
			||||||
@ -27872,9 +28062,8 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
 | 
				
			|||||||
    JSValueConst *resolving_funcs = argv;
 | 
					    JSValueConst *resolving_funcs = argv;
 | 
				
			||||||
    JSValueConst basename_val = argv[2];
 | 
					    JSValueConst basename_val = argv[2];
 | 
				
			||||||
    JSValueConst specifier = argv[3];
 | 
					    JSValueConst specifier = argv[3];
 | 
				
			||||||
    JSModuleDef *m;
 | 
					 | 
				
			||||||
    const char *basename = NULL, *filename;
 | 
					    const char *basename = NULL, *filename;
 | 
				
			||||||
    JSValue ret, err, ns;
 | 
					    JSValue ret, err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!JS_IsString(basename_val)) {
 | 
					    if (!JS_IsString(basename_val)) {
 | 
				
			||||||
        JS_ThrowTypeError(ctx, "no function filename for import()");
 | 
					        JS_ThrowTypeError(ctx, "no function filename for import()");
 | 
				
			||||||
@ -27888,24 +28077,12 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
 | 
				
			|||||||
    if (!filename)
 | 
					    if (!filename)
 | 
				
			||||||
        goto exception;
 | 
					        goto exception;
 | 
				
			||||||
                     
 | 
					                     
 | 
				
			||||||
    m = JS_RunModule(ctx, basename, filename);
 | 
					    JS_LoadModuleInternal(ctx, basename, filename,
 | 
				
			||||||
 | 
					                          resolving_funcs);
 | 
				
			||||||
    JS_FreeCString(ctx, filename);
 | 
					    JS_FreeCString(ctx, filename);
 | 
				
			||||||
    if (!m)
 | 
					 | 
				
			||||||
        goto exception;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* return the module namespace */
 | 
					 | 
				
			||||||
    ns = js_get_module_ns(ctx, m);
 | 
					 | 
				
			||||||
    if (JS_IsException(ns))
 | 
					 | 
				
			||||||
        goto exception;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
 | 
					 | 
				
			||||||
                   1, (JSValueConst *)&ns);
 | 
					 | 
				
			||||||
    JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
 | 
					 | 
				
			||||||
    JS_FreeValue(ctx, ns);
 | 
					 | 
				
			||||||
    JS_FreeCString(ctx, basename);
 | 
					    JS_FreeCString(ctx, basename);
 | 
				
			||||||
    return JS_UNDEFINED;
 | 
					    return JS_UNDEFINED;
 | 
				
			||||||
 exception:
 | 
					 exception:
 | 
				
			||||||
 | 
					 | 
				
			||||||
    err = JS_GetException(ctx);
 | 
					    err = JS_GetException(ctx);
 | 
				
			||||||
    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
 | 
					    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
 | 
				
			||||||
                   1, (JSValueConst *)&err);
 | 
					                   1, (JSValueConst *)&err);
 | 
				
			||||||
@ -27941,6 +28118,8 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
 | 
				
			|||||||
    args[2] = basename_val;
 | 
					    args[2] = basename_val;
 | 
				
			||||||
    args[3] = specifier;
 | 
					    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_EnqueueJob(ctx, js_dynamic_import_job, 4, args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    JS_FreeValue(ctx, basename_val);
 | 
					    JS_FreeValue(ctx, basename_val);
 | 
				
			||||||
@ -27949,60 +28128,397 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
 | 
				
			|||||||
    return promise;
 | 
					    return promise;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Run the <eval> function of the module and of all its requested
 | 
					static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m)
 | 
				
			||||||
   modules. */
 | 
					{
 | 
				
			||||||
static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
 | 
					    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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
					    JSModuleDef *m1;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
    JSValue ret_val;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (m->eval_mark)
 | 
					    if (js_check_stack_overflow(ctx->rt, 0)) {
 | 
				
			||||||
        return JS_UNDEFINED; /* avoid cycles */
 | 
					        JS_ThrowStackOverflow(ctx);
 | 
				
			||||||
 | 
					        *pvalue = JS_GetException(ctx);
 | 
				
			||||||
    if (m->evaluated) {
 | 
					        return -1;
 | 
				
			||||||
        /* if the module was already evaluated, rethrow the exception
 | 
					 | 
				
			||||||
           it raised */
 | 
					 | 
				
			||||||
        if (m->eval_has_exception) {
 | 
					 | 
				
			||||||
            return JS_Throw(ctx, JS_DupValue(ctx, m->eval_exception));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            return JS_UNDEFINED;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    for(i = 0; i < m->req_module_entries_count; i++) {
 | 
					    for(i = 0; i < m->req_module_entries_count; i++) {
 | 
				
			||||||
        JSReqModuleEntry *rme = &m->req_module_entries[i];
 | 
					        JSReqModuleEntry *rme = &m->req_module_entries[i];
 | 
				
			||||||
        m1 = rme->module;
 | 
					        m1 = rme->module;
 | 
				
			||||||
        if (!m1->eval_mark) {
 | 
					        index = js_inner_module_evaluation(ctx, m1, index, pstack_top, pvalue);
 | 
				
			||||||
            ret_val = js_evaluate_module(ctx, m1);
 | 
					        if (index < 0) 
 | 
				
			||||||
            if (JS_IsException(ret_val)) {
 | 
					            return -1;
 | 
				
			||||||
                m->eval_mark = FALSE;
 | 
					        assert(m1->status == JS_MODULE_STATUS_EVALUATING ||
 | 
				
			||||||
                return ret_val;
 | 
					               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;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            JS_FreeValue(ctx, ret_val);
 | 
					        }
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (m->init_func) {
 | 
					    if (m->pending_async_dependencies > 0) {
 | 
				
			||||||
        /* C module init */
 | 
					        assert(!m->async_evaluation);
 | 
				
			||||||
        if (m->init_func(ctx, m) < 0)
 | 
					        m->async_evaluation = TRUE;
 | 
				
			||||||
            ret_val = JS_EXCEPTION;
 | 
					        m->async_evaluation_timestamp =
 | 
				
			||||||
        else
 | 
					            ctx->rt->module_async_evaluation_next_timestamp++;
 | 
				
			||||||
            ret_val = JS_UNDEFINED;
 | 
					    } 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 {
 | 
					    } else {
 | 
				
			||||||
        ret_val = JS_CallFree(ctx, m->func_obj, JS_UNDEFINED, 0, NULL);
 | 
					        if (js_execute_sync_module(ctx, m, pvalue) < 0)
 | 
				
			||||||
        m->func_obj = JS_UNDEFINED;
 | 
					            return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (JS_IsException(ret_val)) {
 | 
					
 | 
				
			||||||
        /* save the thrown exception value */
 | 
					    assert(m->dfs_ancestor_index <= m->dfs_index);
 | 
				
			||||||
        m->eval_has_exception = TRUE;
 | 
					    if (m->dfs_index == m->dfs_ancestor_index) {
 | 
				
			||||||
        m->eval_exception = JS_DupValue(ctx, ctx->rt->current_exception);
 | 
					        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;
 | 
					    *pvalue = JS_UNDEFINED;
 | 
				
			||||||
    m->evaluated = TRUE;
 | 
					    return index;
 | 
				
			||||||
    return ret_val;
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Run the <eval> 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)
 | 
					static __exception JSAtom js_parse_from_clause(JSParseState *s)
 | 
				
			||||||
@ -33217,7 +33733,7 @@ static __exception int js_parse_program(JSParseState *s)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        emit_op(s, OP_return);
 | 
					        emit_op(s, OP_return);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        emit_op(s, OP_return_undef);
 | 
					        emit_return(s, FALSE);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@ -33260,7 +33776,6 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
 | 
				
			|||||||
        ret_val = js_evaluate_module(ctx, m);
 | 
					        ret_val = js_evaluate_module(ctx, m);
 | 
				
			||||||
        if (JS_IsException(ret_val)) {
 | 
					        if (JS_IsException(ret_val)) {
 | 
				
			||||||
        fail:
 | 
					        fail:
 | 
				
			||||||
            js_free_modules(ctx, JS_FREE_MODULE_NOT_EVALUATED);
 | 
					 | 
				
			||||||
            return JS_EXCEPTION;
 | 
					            return JS_EXCEPTION;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@ -33373,6 +33888,10 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
 | 
				
			|||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fd->module = m;
 | 
					    fd->module = m;
 | 
				
			||||||
 | 
					    if (m != NULL) {
 | 
				
			||||||
 | 
					        fd->in_function_body = TRUE;
 | 
				
			||||||
 | 
					        fd->func_kind = JS_FUNC_ASYNC;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->is_module = (m != NULL);
 | 
					    s->is_module = (m != NULL);
 | 
				
			||||||
    s->allow_html_comments = !s->is_module;
 | 
					    s->allow_html_comments = !s->is_module;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -33387,6 +33906,9 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
 | 
				
			|||||||
        goto fail1;
 | 
					        goto fail1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (m != NULL)
 | 
				
			||||||
 | 
					        m->has_tla = fd->has_await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* create the function object and all the enclosed functions */
 | 
					    /* create the function object and all the enclosed functions */
 | 
				
			||||||
    fun_obj = js_create_function(ctx, fd);
 | 
					    fun_obj = js_create_function(ctx, fd);
 | 
				
			||||||
    if (JS_IsException(fun_obj))
 | 
					    if (JS_IsException(fun_obj))
 | 
				
			||||||
@ -33396,7 +33918,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
 | 
				
			|||||||
        m->func_obj = fun_obj;
 | 
					        m->func_obj = fun_obj;
 | 
				
			||||||
        if (js_resolve_module(ctx, m) < 0)
 | 
					        if (js_resolve_module(ctx, m) < 0)
 | 
				
			||||||
            goto fail1;
 | 
					            goto fail1;
 | 
				
			||||||
        fun_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
 | 
					        fun_obj = JS_NewModuleValue(ctx, m);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
 | 
					    if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
 | 
				
			||||||
        ret_val = fun_obj;
 | 
					        ret_val = fun_obj;
 | 
				
			||||||
@ -34143,6 +34665,8 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
 | 
				
			|||||||
        bc_put_leb128(s, mi->req_module_idx);
 | 
					        bc_put_leb128(s, mi->req_module_idx);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bc_put_u8(s, m->has_tla);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    if (JS_WriteObjectRec(s, m->func_obj))
 | 
					    if (JS_WriteObjectRec(s, m->func_obj))
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@ -35153,7 +35677,7 @@ static JSValue JS_ReadModule(BCReaderState *s)
 | 
				
			|||||||
    m = js_new_module_def(ctx, module_name);
 | 
					    m = js_new_module_def(ctx, module_name);
 | 
				
			||||||
    if (!m)
 | 
					    if (!m)
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
 | 
					    obj = JS_NewModuleValue(ctx, m);
 | 
				
			||||||
    if (bc_get_leb128_int(s, &m->req_module_entries_count))
 | 
					    if (bc_get_leb128_int(s, &m->req_module_entries_count))
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    if (m->req_module_entries_count != 0) {
 | 
					    if (m->req_module_entries_count != 0) {
 | 
				
			||||||
@ -35226,6 +35750,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);
 | 
					    m->func_obj = JS_ReadObjectRec(s);
 | 
				
			||||||
    if (JS_IsException(m->func_obj))
 | 
					    if (JS_IsException(m->func_obj))
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
@ -46148,12 +46676,6 @@ static const JSCFunctionListEntry js_generator_proto_funcs[] = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Promise */
 | 
					/* Promise */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum JSPromiseStateEnum {
 | 
					 | 
				
			||||||
    JS_PROMISE_PENDING,
 | 
					 | 
				
			||||||
    JS_PROMISE_FULFILLED,
 | 
					 | 
				
			||||||
    JS_PROMISE_REJECTED,
 | 
					 | 
				
			||||||
} JSPromiseStateEnum;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct JSPromiseData {
 | 
					typedef struct JSPromiseData {
 | 
				
			||||||
    JSPromiseStateEnum promise_state;
 | 
					    JSPromiseStateEnum promise_state;
 | 
				
			||||||
    /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */
 | 
					    /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */
 | 
				
			||||||
@ -46178,6 +46700,22 @@ typedef struct JSPromiseReactionData {
 | 
				
			|||||||
    JSValue handler;
 | 
					    JSValue handler;
 | 
				
			||||||
} JSPromiseReactionData;
 | 
					} JSPromiseReactionData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
 | 
				
			||||||
 | 
					    if (!s)
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    return s->promise_state;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					JSValue JS_PromiseResult(JSContext *ctx, JSValue promise)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
 | 
				
			||||||
 | 
					    if (!s)
 | 
				
			||||||
 | 
					        return JS_UNDEFINED;
 | 
				
			||||||
 | 
					    return JS_DupValue(ctx, s->promise_result);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int js_create_resolving_functions(JSContext *ctx, JSValue *args,
 | 
					static int js_create_resolving_functions(JSContext *ctx, JSValue *args,
 | 
				
			||||||
                                         JSValueConst promise);
 | 
					                                         JSValueConst promise);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								quickjs.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								quickjs.h
									
									
									
									
									
								
							@ -831,7 +831,15 @@ typedef struct {
 | 
				
			|||||||
void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
 | 
					void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
 | 
				
			||||||
                                      const JSSharedArrayBufferFunctions *sf);
 | 
					                                      const JSSharedArrayBufferFunctions *sf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum JSPromiseStateEnum {
 | 
				
			||||||
 | 
					    JS_PROMISE_PENDING,
 | 
				
			||||||
 | 
					    JS_PROMISE_FULFILLED,
 | 
				
			||||||
 | 
					    JS_PROMISE_REJECTED,
 | 
				
			||||||
 | 
					} JSPromiseStateEnum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
 | 
					JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
 | 
				
			||||||
 | 
					JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise);
 | 
				
			||||||
 | 
					JSValue JS_PromiseResult(JSContext *ctx, JSValue promise);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* is_handled = TRUE means that the rejection is handled */
 | 
					/* is_handled = TRUE means that the rejection is handled */
 | 
				
			||||||
typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise,
 | 
					typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise,
 | 
				
			||||||
@ -902,8 +910,8 @@ int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
 | 
				
			|||||||
/* only exported for os.Worker() */
 | 
					/* only exported for os.Worker() */
 | 
				
			||||||
JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
 | 
					JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
 | 
				
			||||||
/* only exported for os.Worker() */
 | 
					/* only exported for os.Worker() */
 | 
				
			||||||
JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
 | 
					JSValue JS_LoadModule(JSContext *ctx, const char *basename,
 | 
				
			||||||
                          const char *filename);
 | 
					                      const char *filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* C function definition */
 | 
					/* C function definition */
 | 
				
			||||||
typedef enum JSCFunctionEnum {  /* XXX: should rename for namespace isolation */
 | 
					typedef enum JSCFunctionEnum {  /* XXX: should rename for namespace isolation */
 | 
				
			||||||
 | 
				
			|||||||
@ -1174,7 +1174,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    JSValue res_val, exception_val;
 | 
					    JSValue res_val, exception_val;
 | 
				
			||||||
    int ret, error_line, pos, pos_line;
 | 
					    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;
 | 
					    const char *error_name;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    pos = skip_comments(buf, 1, &pos_line);
 | 
					    pos = skip_comments(buf, 1, &pos_line);
 | 
				
			||||||
@ -1183,12 +1183,19 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
 | 
				
			|||||||
    exception_val = JS_UNDEFINED;
 | 
					    exception_val = JS_UNDEFINED;
 | 
				
			||||||
    error_name = NULL;
 | 
					    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 */
 | 
					    async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
 | 
					    res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (is_async && !JS_IsException(res_val)) {
 | 
					    if ((is_async || ret_promise) && !JS_IsException(res_val)) {
 | 
				
			||||||
        JS_FreeValue(ctx, res_val);
 | 
					        JSValue promise = JS_UNDEFINED;
 | 
				
			||||||
 | 
					        if (ret_promise) {
 | 
				
			||||||
 | 
					            promise = res_val;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            JS_FreeValue(ctx, res_val);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        for(;;) {
 | 
					        for(;;) {
 | 
				
			||||||
            JSContext *ctx1;
 | 
					            JSContext *ctx1;
 | 
				
			||||||
            ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
 | 
					            ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
 | 
				
			||||||
@ -1196,15 +1203,27 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
 | 
				
			|||||||
                res_val = JS_EXCEPTION;
 | 
					                res_val = JS_EXCEPTION;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            } else if (ret == 0) {
 | 
					            } else if (ret == 0) {
 | 
				
			||||||
                /* test if the test called $DONE() once */
 | 
					                if (is_async) {
 | 
				
			||||||
                if (async_done != 1) {
 | 
					                    /* test if the test called $DONE() once */
 | 
				
			||||||
                    res_val = JS_ThrowTypeError(ctx, "$DONE() not called");
 | 
					                    if (async_done != 1) {
 | 
				
			||||||
 | 
					                        res_val = JS_ThrowTypeError(ctx, "$DONE() not called");
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        res_val = JS_UNDEFINED;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                } else {
 | 
					                } 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;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        JS_FreeValue(ctx, promise);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (JS_IsException(res_val)) {
 | 
					    if (JS_IsException(res_val)) {
 | 
				
			||||||
 | 
				
			|||||||
@ -195,7 +195,7 @@ symbols-as-weakmap-keys=skip
 | 
				
			|||||||
tail-call-optimization=skip
 | 
					tail-call-optimization=skip
 | 
				
			||||||
template
 | 
					template
 | 
				
			||||||
Temporal=skip
 | 
					Temporal=skip
 | 
				
			||||||
top-level-await=skip
 | 
					top-level-await
 | 
				
			||||||
TypedArray
 | 
					TypedArray
 | 
				
			||||||
TypedArray.prototype.at
 | 
					TypedArray.prototype.at
 | 
				
			||||||
u180e
 | 
					u180e
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user