MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix async event loop while in server

+168 -18
+1 -1
examples/server/server.js
··· 28 28 }); 29 29 30 30 router.insert('/status', async c => { 31 - await new Promise(resolve => setTimeout(resolve, 100)); 31 + await new Promise(resolve => setTimeout(resolve, 1000)); 32 32 const result = await Promise.resolve('Hello'); 33 33 // const result = (await fetch('http://localhost:8000/meow')).text(); 34 34 return c.res.body(`server is responding with ${result}`);
+1 -1
include/ant.h
··· 9 9 10 10 enum { 11 11 JS_UNDEF, JS_NULL, JS_TRUE, JS_FALSE, 12 - JS_STR, JS_NUM, JS_ERR, JS_PRIV 12 + JS_STR, JS_NUM, JS_ERR, JS_PRIV, JS_PROMISE 13 13 }; 14 14 15 15 struct js *js_create(void *buf, size_t len);
+1 -1
meson.build
··· 67 67 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 68 68 69 69 version_conf = configuration_data() 70 - version_conf.set('ANT_VERSION', '0.0.6.24') 70 + version_conf.set('ANT_VERSION', '0.0.6.25') 71 71 version_conf.set('ANT_GIT_HASH', git_hash) 72 72 version_conf.set('ANT_BUILD_DATE', build_date) 73 73
+134 -11
src/ant.c
··· 298 298 static jsval_t builtin_Date_now(struct js *js, jsval_t *args, int nargs); 299 299 300 300 static jsval_t call_js(struct js *js, const char *fn, jsoff_t fnlen, jsval_t closure_scope); 301 - static jsval_t start_async_in_coroutine(struct js *js, const char *code, size_t code_len, jsval_t closure_scope); 301 + static jsval_t call_js_with_args(struct js *js, jsval_t func, jsval_t *args, int nargs); 302 + static jsval_t call_js_code_with_args(struct js *js, const char *fn, jsoff_t fnlen, jsval_t closure_scope, jsval_t *args, int nargs); 303 + static jsval_t start_async_in_coroutine(struct js *js, const char *code, size_t code_len, jsval_t closure_scope, jsval_t *args, int nargs); 302 304 303 305 static void free_coroutine(coroutine_t *coro); 304 306 static bool has_ready_coroutines(void); ··· 307 309 async_exec_context_t *ctx = (async_exec_context_t *)mco_get_user_data(mco); 308 310 309 311 struct js *js = ctx->js; 310 - jsval_t result = call_js(js, ctx->code, (jsoff_t)ctx->code_len, ctx->closure_scope); 312 + coroutine_t *coro = ctx->coro; 313 + jsval_t result; 314 + 315 + if (coro && coro->nargs > 0 && coro->args) { 316 + result = call_js_code_with_args(js, ctx->code, (jsoff_t)ctx->code_len, ctx->closure_scope, coro->args, coro->nargs); 317 + } else { 318 + result = call_js(js, ctx->code, (jsoff_t)ctx->code_len, ctx->closure_scope); 319 + } 311 320 312 321 ctx->result = result; 313 322 ctx->has_error = is_err(result); ··· 420 429 421 430 void js_poll_events(struct js *js) { 422 431 fetch_poll_events(); 432 + int has_timers = has_pending_timers(); 423 433 424 - if (has_pending_timers()) { 434 + if (has_timers) { 425 435 int64_t next_timeout_ms = get_next_timer_timeout(); 426 436 if (next_timeout_ms <= 0) process_timers(js); 427 437 } ··· 485 495 js_poll_events(js); 486 496 } 487 497 488 - static jsval_t start_async_in_coroutine(struct js *js, const char *code, size_t code_len, jsval_t closure_scope) { 498 + static jsval_t start_async_in_coroutine(struct js *js, const char *code, size_t code_len, jsval_t closure_scope, jsval_t *args, int nargs) { 489 499 jsval_t promise = js_mkpromise(js); 490 500 async_exec_context_t *ctx = (async_exec_context_t *)malloc(sizeof(async_exec_context_t)); 491 501 if (!ctx) return js_mkerr(js, "out of memory for async context"); ··· 523 533 coro->awaited_promise = js_mkundef(); 524 534 coro->result = js_mkundef(); 525 535 coro->async_func = js->current_func; 526 - coro->args = NULL; 527 - coro->nargs = 0; 536 + if (nargs > 0) { 537 + coro->args = (jsval_t *)malloc(sizeof(jsval_t) * nargs); 538 + if (coro->args) memcpy(coro->args, args, sizeof(jsval_t) * nargs); 539 + } else { 540 + coro->args = NULL; 541 + } 542 + coro->nargs = nargs; 528 543 coro->is_settled = false; 529 544 coro->is_error = false; 530 545 coro->is_done = false; ··· 1946 1961 size_t body_len = fnlen - fnpos - 1; 1947 1962 1948 1963 jsval_t saved_this = js->this_val; 1949 - js->this_val = js_glob(js); 1964 + jsval_t target_this = peek_this(); 1965 + js->this_val = target_this; 1966 + js->flags = F_CALL; 1967 + 1968 + jsval_t res = js_eval(js, &fn[fnpos], body_len); 1969 + if (!is_err(res) && !(js->flags & F_RETURN)) res = js_mkundef(); 1970 + 1971 + js->this_val = saved_this; 1972 + js->scope = saved_scope; 1973 + 1974 + return res; 1975 + } 1976 + 1977 + static jsval_t call_js_code_with_args(struct js *js, const char *fn, jsoff_t fnlen, jsval_t closure_scope, jsval_t *args, int nargs) { 1978 + jsoff_t parent_scope_offset; 1979 + if (vtype(closure_scope) == T_OBJ) { 1980 + parent_scope_offset = (jsoff_t) vdata(closure_scope); 1981 + } else { 1982 + parent_scope_offset = (jsoff_t) vdata(js->scope); 1983 + } 1984 + 1985 + jsval_t saved_scope = js->scope; 1986 + jsval_t function_scope = mkobj(js, parent_scope_offset); 1987 + js->scope = function_scope; 1988 + 1989 + jsoff_t fnpos = 1; 1990 + int arg_idx = 0; 1991 + bool has_rest = false; 1992 + jsoff_t rest_param_start = 0, rest_param_len = 0; 1993 + 1994 + while (fnpos < fnlen) { 1995 + fnpos = skiptonext(fn, fnlen, fnpos); 1996 + if (fnpos < fnlen && fn[fnpos] == ')') break; 1997 + 1998 + bool is_rest = false; 1999 + if (fnpos + 3 < fnlen && fn[fnpos] == '.' && fn[fnpos + 1] == '.' && fn[fnpos + 2] == '.') { 2000 + is_rest = true; 2001 + has_rest = true; 2002 + fnpos += 3; 2003 + fnpos = skiptonext(fn, fnlen, fnpos); 2004 + } 2005 + 2006 + jsoff_t identlen = 0; 2007 + uint8_t tok = parseident(&fn[fnpos], fnlen - fnpos, &identlen); 2008 + if (tok != TOK_IDENTIFIER) break; 2009 + 2010 + if (is_rest) { 2011 + rest_param_start = fnpos; 2012 + rest_param_len = identlen; 2013 + fnpos = skiptonext(fn, fnlen, fnpos + identlen); 2014 + break; 2015 + } 2016 + 2017 + jsval_t v = arg_idx < nargs ? args[arg_idx] : js_mkundef(); 2018 + setprop(js, function_scope, js_mkstr(js, &fn[fnpos], identlen), v); 2019 + arg_idx++; 2020 + fnpos = skiptonext(fn, fnlen, fnpos + identlen); 2021 + if (fnpos < fnlen && fn[fnpos] == ',') fnpos++; 2022 + } 2023 + 2024 + if (has_rest && rest_param_len > 0) { 2025 + jsval_t rest_array = mkarr(js); 2026 + if (!is_err(rest_array)) { 2027 + jsoff_t idx = 0; 2028 + while (arg_idx < nargs) { 2029 + char idxstr[16]; 2030 + snprintf(idxstr, sizeof(idxstr), "%u", (unsigned) idx); 2031 + jsval_t key = js_mkstr(js, idxstr, strlen(idxstr)); 2032 + setprop(js, rest_array, key, args[arg_idx]); 2033 + idx++; 2034 + arg_idx++; 2035 + } 2036 + jsval_t len_key = js_mkstr(js, "length", 6); 2037 + setprop(js, rest_array, len_key, tov((double) idx)); 2038 + rest_array = mkval(T_ARR, vdata(rest_array)); 2039 + setprop(js, function_scope, js_mkstr(js, &fn[rest_param_start], rest_param_len), rest_array); 2040 + } 2041 + } 2042 + 2043 + if (fnpos < fnlen && fn[fnpos] == ')') fnpos++; 2044 + fnpos = skiptonext(fn, fnlen, fnpos); 2045 + if (fnpos < fnlen && fn[fnpos] == '{') fnpos++; 2046 + size_t body_len = fnlen - fnpos - 1; 2047 + 2048 + jsval_t saved_this = js->this_val; 2049 + jsval_t target_this = peek_this(); 2050 + js->this_val = target_this; 1950 2051 js->flags = F_CALL; 1951 2052 1952 2053 jsval_t res = js_eval(js, &fn[fnpos], body_len); ··· 2024 2125 js->nogc = (jsoff_t) (fnoff - sizeof(jsoff_t)); 2025 2126 2026 2127 if (is_async) { 2027 - res = start_async_in_coroutine(js, code_str, fnlen, closure_scope); 2128 + res = start_async_in_coroutine(js, code_str, fnlen, closure_scope, NULL, 0); 2028 2129 pop_call_frame(); 2029 2130 } else { 2030 2131 res = call_js(js, code_str, fnlen, closure_scope); ··· 3096 3197 jsval_t then_args[] = { resume_fn, reject_fn }; 3097 3198 jsval_t saved_this = js->this_val; 3098 3199 js->this_val = resolved; 3099 - builtin_promise_then(js, then_args, 2); 3200 + (void)builtin_promise_then(js, then_args, 2); 3100 3201 js->this_val = saved_this; 3101 3202 3102 3203 uint8_t saved_flags = js->flags; ··· 6257 6358 static void resolve_promise(struct js *js, jsval_t p, jsval_t val) { 6258 6359 jsval_t p_obj = mkval(T_OBJ, vdata(p)); 6259 6360 jsoff_t state_off = lkp(js, p_obj, "__state", 7); 6260 - if (state_off == 0) return; 6361 + if (state_off == 0) { 6362 + return; 6363 + } 6261 6364 jsval_t state_val = resolveprop(js, mkval(T_PROP, state_off)); 6262 - if ((int)tod(state_val) != 0) return; 6365 + if ((int)tod(state_val) != 0) { 6366 + return; 6367 + } 6263 6368 6264 6369 if (vtype(val) == T_PROMISE) { 6265 6370 if (vdata(val) == vdata(p)) { ··· 7612 7717 case T_STR: return JS_STR; 7613 7718 case T_NUM: return JS_NUM; 7614 7719 case T_ERR: return JS_ERR; 7720 + case T_PROMISE: return JS_PROMISE; 7615 7721 default: return JS_PRIV; 7616 7722 } 7617 7723 } ··· 7694 7800 if (vtype(code_val) != T_STR) return js_mkerr(js, "function code not string"); 7695 7801 jsoff_t fnlen, fnoff = vstr(js, code_val, &fnlen); 7696 7802 const char *fn = (const char *) (&js->mem[fnoff]); 7803 + 7804 + jsoff_t async_off = lkp(js, func_obj, "__async", 7); 7805 + bool is_async = false; 7806 + if (async_off != 0) { 7807 + jsval_t async_val = resolveprop(js, mkval(T_PROP, async_off)); 7808 + is_async = vtype(async_val) == T_BOOL && vdata(async_val) == 1; 7809 + } 7810 + 7811 + if (is_async) { 7812 + jsval_t closure_scope = js_mkundef(); 7813 + jsoff_t scope_off = lkp(js, func_obj, "__scope", 7); 7814 + if (scope_off != 0) { 7815 + closure_scope = resolveprop(js, mkval(T_PROP, scope_off)); 7816 + } 7817 + return start_async_in_coroutine(js, fn, fnlen, closure_scope, args, nargs); 7818 + } 7819 + 7697 7820 jsoff_t fnpos = 1; 7698 7821 7699 7822 jsval_t saved_scope = js->scope;
+2
src/modules/fetch.c
··· 325 325 } 326 326 327 327 void fetch_poll_events(void) { 328 + if (fetch_loop && fetch_loop == uv_default_loop()) return; 329 + 328 330 if (fetch_loop && uv_loop_alive(fetch_loop)) { 329 331 uv_run(fetch_loop, UV_RUN_ONCE); 330 332 if (pending_requests && utarray_len(pending_requests) > 0) usleep(1000);
+29 -4
src/modules/server.c
··· 49 49 static uv_loop_t *g_loop = NULL; 50 50 static int g_loop_initialized = 0; 51 51 static uv_timer_t g_js_timer; 52 - static struct js *g_js = NULL; 53 52 54 53 static void server_signal_handler(int signum) { 55 54 (void)signum; ··· 58 57 } 59 58 60 59 static void on_js_timer(uv_timer_t *handle) { 61 - (void)handle; 60 + struct js *js = (struct js*)handle->data; 61 + if (js && has_pending_timers()) { 62 + int64_t next_timeout = get_next_timer_timeout(); 63 + if (next_timeout <= 0) process_timers(js); 64 + } 62 65 } 63 66 64 67 typedef struct { ··· 130 133 static void on_close(uv_handle_t *handle); 131 134 static void send_response(uv_stream_t *client, response_ctx_t *res_ctx); 132 135 136 + typedef struct { 137 + http_server_t *server; 138 + response_ctx_t *res_ctx; 139 + } promise_callback_data_t; 140 + 141 + static jsval_t promise_then_callback(struct js *js, jsval_t *args, int nargs) { 142 + (void)js; 143 + (void)args; 144 + (void)nargs; 145 + // The promise resolved, response should have been sent via res.body() etc 146 + // Mark as sent if not already sent (for cases where handler doesn't call res methods) 147 + // This will be handled by check_pending_responses in the event loop 148 + return js_mkundef(); 149 + } 150 + 133 151 static jsval_t res_status(struct js *js, jsval_t *args, int nargs) { 134 152 if (nargs < 1) return js_mkundef(); 135 153 ··· 319 337 res_ctx->body = "Internal Server Error"; 320 338 res_ctx->content_type = "text/plain"; 321 339 res_ctx->sent = 1; 340 + } else if (js_type(result) == JS_PROMISE) { 341 + jsval_t then_fn = js_get(server->js, result, "then"); 342 + if (js_type(then_fn) != JS_UNDEF) { 343 + jsval_t callback = js_mkfun(promise_then_callback); 344 + jsval_t then_args[1] = {callback}; 345 + js_call(server->js, then_fn, then_args, 1); 346 + } 347 + return; 322 348 } else if (!res_ctx->sent) { 323 349 res_ctx->status = 404; 324 350 res_ctx->body = "Not Found"; ··· 515 541 } 516 542 517 543 server->pending_responses = NULL; 518 - g_js = js; 519 544 520 545 uv_timer_init(g_loop, &g_js_timer); 546 + g_js_timer.data = js; 521 547 522 548 while (uv_loop_alive(g_loop)) { 523 549 if (has_pending_timers()) { ··· 530 556 531 557 uv_run(g_loop, UV_RUN_ONCE); 532 558 js_poll_events(js); 533 - 534 559 check_pending_responses(server); 535 560 } 536 561