From: Alexander Borisov Date: Thu, 2 Sep 2021 16:32:27 +0000 (+0300) Subject: Fixed async ctx erasing when a function is called multiple times. X-Git-Tag: 0.7.0~26 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=411d477fe4be1b30b53246866fbd846eb8575f00;p=njs.git Fixed async ctx erasing when a function is called multiple times. The bug was introduced in 92d10cd761e2. --- diff --git a/src/njs_async.c b/src/njs_async.c index 3c8c95db..97ce87ff 100644 --- a/src/njs_async.c +++ b/src/njs_async.c @@ -8,33 +8,33 @@ static void -njs_async_context_free(njs_vm_t *vm, njs_native_frame_t *frame); +njs_async_context_free(njs_vm_t *vm, njs_async_ctx_t *ctx); njs_int_t njs_async_function_frame_invoke(njs_vm_t *vm, njs_value_t *retval) { - njs_int_t ret; - njs_value_t ctor; - njs_async_ctx_t *ctx; - njs_native_frame_t *frame; + njs_int_t ret; + njs_value_t ctor; + njs_native_frame_t *frame; + njs_promise_capability_t *capability; frame = vm->top_frame; frame->retval = retval; - ctx = frame->function->context; - njs_set_function(&ctor, &vm->constructors[NJS_OBJ_TYPE_PROMISE]); - ctx->capability = njs_promise_new_capability(vm, &ctor); - if (njs_slow_path(ctx->capability == NULL)) { + capability = njs_promise_new_capability(vm, &ctor); + if (njs_slow_path(capability == NULL)) { return NJS_ERROR; } + frame->function->context = capability; + ret = njs_function_lambda_call(vm); if (ret == NJS_OK) { - ret = njs_function_call(vm, njs_function(&ctx->capability->resolve), + ret = njs_function_call(vm, njs_function(&capability->resolve), &njs_value_undefined, retval, 1, &vm->retval); } else if (ret == NJS_ERROR) { @@ -42,12 +42,12 @@ njs_async_function_frame_invoke(njs_vm_t *vm, njs_value_t *retval) return NJS_ERROR; } - ret = njs_function_call(vm, njs_function(&ctx->capability->reject), + ret = njs_function_call(vm, njs_function(&capability->reject), &njs_value_undefined, &vm->retval, 1, &vm->retval); } - *retval = ctx->capability->promise; + *retval = capability->promise; return ret; } @@ -60,6 +60,7 @@ njs_await_fulfilled(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_int_t ret; njs_value_t **cur_local, **cur_closures, **cur_temp, *value; njs_frame_t *frame; + njs_function_t *function; njs_async_ctx_t *ctx; njs_native_frame_t *top, *async; @@ -71,6 +72,7 @@ njs_await_fulfilled(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } async = ctx->await; + function = async->function; cur_local = vm->levels[NJS_LEVEL_LOCAL]; cur_closures = vm->levels[NJS_LEVEL_CLOSURE]; @@ -90,8 +92,14 @@ njs_await_fulfilled(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, vm->top_frame->retval = &vm->retval; + function->context = ctx->capability; + function->await = ctx; + ret = njs_vmcode_interpreter(vm, ctx->pc); + function->context = NULL; + function->await = NULL; + vm->levels[NJS_LEVEL_LOCAL] = cur_local; vm->levels[NJS_LEVEL_CLOSURE] = cur_closures; vm->levels[NJS_LEVEL_TEMP] = cur_temp; @@ -103,7 +111,7 @@ njs_await_fulfilled(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, ret = njs_function_call(vm, njs_function(&ctx->capability->resolve), &njs_value_undefined, &vm->retval, 1, &vm->retval); - njs_async_context_free(vm, vm->top_frame); + njs_async_context_free(vm, ctx); } else if (ret == NJS_ERROR) { if (njs_is_memory_error(vm, &vm->retval)) { @@ -122,7 +130,7 @@ failed: (void) njs_function_call(vm, njs_function(&ctx->capability->reject), &njs_value_undefined, value, 1, &vm->retval); - njs_async_context_free(vm, vm->top_frame); + njs_async_context_free(vm, ctx); return NJS_ERROR; } @@ -143,7 +151,7 @@ njs_await_rejected(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, (void) njs_function_call(vm, njs_function(&ctx->capability->reject), &njs_value_undefined, value, 1, &vm->retval); - njs_async_context_free(vm, vm->top_frame); + njs_async_context_free(vm, ctx); return NJS_ERROR; } @@ -155,16 +163,10 @@ njs_await_rejected(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, static void -njs_async_context_free(njs_vm_t *vm, njs_native_frame_t *frame) +njs_async_context_free(njs_vm_t *vm, njs_async_ctx_t *ctx) { - njs_async_ctx_t *ctx; - - ctx = frame->function->context; - njs_mp_free(vm->mem_pool, ctx->capability); njs_mp_free(vm->mem_pool, ctx); - - frame->function->context = NULL; } diff --git a/src/njs_function.c b/src/njs_function.c index c3221177..087889cd 100644 --- a/src/njs_function.c +++ b/src/njs_function.c @@ -427,7 +427,6 @@ njs_function_lambda_frame(njs_vm_t *vm, njs_function_t *function, njs_value_t *value, *bound, **new, **temp; njs_frame_t *frame; njs_function_t *target; - njs_async_ctx_t *ctx; njs_native_frame_t *native_frame; njs_function_lambda_t *lambda; @@ -454,17 +453,6 @@ njs_function_lambda_frame(njs_vm_t *vm, njs_function_t *function, lambda = target->u.lambda; } - if (njs_function_object_type(vm, target) == NJS_OBJ_TYPE_ASYNC_FUNCTION) { - ctx = njs_mp_alloc(vm->mem_pool, sizeof(njs_async_ctx_t)); - if (njs_slow_path(ctx == NULL)) { - njs_memory_error(vm); - return NJS_ERROR; - } - - ctx->await = NULL; - target->context = ctx; - } - args_count = function->args_offset + njs_max(nargs, lambda->nargs); value_count = args_count + njs_max(args_count, lambda->nlocal); diff --git a/src/njs_value.h b/src/njs_value.h index f60b8c3d..71eb5233 100644 --- a/src/njs_value.h +++ b/src/njs_value.h @@ -284,6 +284,7 @@ struct njs_function_s { } u; void *context; + void *await; njs_value_t *bound; }; diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c index 8c3d439f..e19a5995 100644 --- a/src/njs_vmcode.c +++ b/src/njs_vmcode.c @@ -1827,7 +1827,6 @@ njs_vmcode_await(njs_vm_t *vm, njs_vmcode_await_t *await) njs_native_frame_t *active; active = &vm->active_frame->native; - ctx = active->function->context; value = njs_scope_valid_value(vm, await->retval); if (njs_slow_path(value == NULL)) { @@ -1841,7 +1840,15 @@ njs_vmcode_await(njs_vm_t *vm, njs_vmcode_await_t *await) return NJS_ERROR; } - if (ctx->await == NULL) { + ctx = active->function->await; + + if (ctx == NULL) { + ctx = njs_mp_alloc(vm->mem_pool, sizeof(njs_async_ctx_t)); + if (njs_slow_path(ctx == NULL)) { + njs_memory_error(vm); + return NJS_ERROR; + } + size = njs_function_frame_size(active); fulfilled = njs_promise_create_function(vm, size); @@ -1850,6 +1857,9 @@ njs_vmcode_await(njs_vm_t *vm, njs_vmcode_await_t *await) } ctx->await = fulfilled->context; + ctx->capability = active->function->context; + + active->function->context = NULL; ret = njs_function_frame_save(vm, ctx->await, NULL); if (njs_slow_path(ret != NJS_OK)) { diff --git a/test/js/async_await_many_call.js b/test/js/async_await_many_call.js new file mode 100644 index 00000000..52f24ac7 --- /dev/null +++ b/test/js/async_await_many_call.js @@ -0,0 +1,30 @@ +async function test(name) { + let k1, k2; + + switch (name) { + case "First": + k1 = await Promise.resolve("SUN"); + k2 = await Promise.resolve("MOON"); + break; + + case "Second": + k1 = await Promise.resolve("CAT"); + k2 = await Promise.resolve("MOUSE"); + break; + + case "Third": + k1 = await Promise.resolve("MAN"); + k2 = await Promise.resolve("WOMAN"); + break; + + default: + break; + } + + return `${name}: ${k1} ${k2}`; +}; + +Promise.all(['First', 'Second', 'Third'].map(v => test(v))) +.then(results => { + console.log(results) +}) diff --git a/test/njs_expect_test.exp b/test/njs_expect_test.exp index 1eb491ee..e04a89ed 100644 --- a/test/njs_expect_test.exp +++ b/test/njs_expect_test.exp @@ -1173,3 +1173,6 @@ end" njs_run {"./test/js/async_await_try_resolve.js"} \ "key: resolve" + +njs_run {"./test/js/async_await_many_call.js"} \ +"\\\['First: SUN MOON','Second: CAT MOUSE','Third: MAN WOMAN']"