blob: c74a6bbabf8eb63d8ea0485b5ff20cc20d17f988 [file] [log] [blame]
/*
* Copyright (C) Alexander Borisov
* Copyright (C) Nginx, Inc.
*/
#include <njs_main.h>
static void
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_native_frame_t *frame;
njs_promise_capability_t *capability;
frame = vm->top_frame;
frame->retval = retval;
njs_set_function(&ctor, &vm->constructors[NJS_OBJ_TYPE_PROMISE]);
capability = njs_promise_new_capability(vm, &ctor);
if (njs_slow_path(capability == NULL)) {
return NJS_ERROR;
}
ret = njs_function_lambda_call(vm, capability);
if (ret == NJS_OK) {
ret = njs_function_call(vm, njs_function(&capability->resolve),
&njs_value_undefined, retval, 1, &vm->retval);
} else if (ret == NJS_AGAIN) {
ret = NJS_OK;
} else if (ret == NJS_ERROR) {
if (njs_is_memory_error(vm, &vm->retval)) {
return NJS_ERROR;
}
ret = njs_function_call(vm, njs_function(&capability->reject),
&njs_value_undefined, &vm->retval, 1,
&vm->retval);
}
*retval = capability->promise;
return ret;
}
njs_int_t
njs_await_fulfilled(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
njs_int_t ret;
njs_value_t **cur_local, **cur_closures, *value;
njs_frame_t *frame, *async_frame;
njs_async_ctx_t *ctx;
njs_native_frame_t *top, *async;
ctx = vm->top_frame->function->context;
value = njs_arg(args, nargs, 1);
async_frame = ctx->await;
async = &async_frame->native;
async->previous = vm->top_frame;
cur_local = vm->levels[NJS_LEVEL_LOCAL];
cur_closures = vm->levels[NJS_LEVEL_CLOSURE];
top = vm->top_frame;
frame = vm->active_frame;
vm->levels[NJS_LEVEL_LOCAL] = async->local;
vm->levels[NJS_LEVEL_CLOSURE] = njs_function_closures(async->function);
vm->top_frame = async;
vm->active_frame = async_frame;
*njs_scope_value(vm, ctx->index) = *value;
vm->retval = *value;
vm->top_frame->retval = &vm->retval;
ret = njs_vmcode_interpreter(vm, ctx->pc, ctx->capability, ctx);
vm->levels[NJS_LEVEL_LOCAL] = cur_local;
vm->levels[NJS_LEVEL_CLOSURE] = cur_closures;
vm->top_frame = top;
vm->active_frame = frame;
if (ret == NJS_OK) {
ret = njs_function_call(vm, njs_function(&ctx->capability->resolve),
&njs_value_undefined, &vm->retval, 1, &vm->retval);
njs_async_context_free(vm, ctx);
} else if (ret == NJS_AGAIN) {
ret = NJS_OK;
} else if (ret == NJS_ERROR) {
if (njs_is_memory_error(vm, &vm->retval)) {
return NJS_ERROR;
}
value = &vm->retval;
goto failed;
}
return ret;
failed:
(void) njs_function_call(vm, njs_function(&ctx->capability->reject),
&njs_value_undefined, value, 1, &vm->retval);
njs_async_context_free(vm, ctx);
return NJS_ERROR;
}
njs_int_t
njs_await_rejected(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
njs_value_t *value;
njs_async_ctx_t *ctx;
ctx = vm->top_frame->function->context;
value = njs_arg(args, nargs, 1);
if (ctx->await->native.pc == ctx->pc) {
/* No catch block was set before await. */
(void) njs_function_call(vm, njs_function(&ctx->capability->reject),
&njs_value_undefined, value, 1, &vm->retval);
njs_async_context_free(vm, ctx);
return NJS_ERROR;
}
/* ctx->await->native.pc points to a catch block here. */
ctx->pc = ctx->await->native.pc;
return njs_await_fulfilled(vm, args, nargs, unused);
}
static void
njs_async_context_free(njs_vm_t *vm, njs_async_ctx_t *ctx)
{
njs_mp_free(vm->mem_pool, ctx->capability);
njs_mp_free(vm->mem_pool, ctx);
}
static const njs_object_prop_t njs_async_constructor_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("length"),
.value = njs_value(NJS_NUMBER, 1, 1.0),
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
.value = njs_prop_handler(njs_object_prototype_create),
},
};
const njs_object_init_t njs_async_constructor_init = {
njs_async_constructor_properties,
njs_nitems(njs_async_constructor_properties),
};
static const njs_object_prop_t njs_async_prototype_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG),
.value = njs_string("AsyncFunction"),
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("constructor"),
.value = njs_prop_handler(njs_object_prototype_create_constructor),
.configurable = 1,
},
};
const njs_object_init_t njs_async_prototype_init = {
njs_async_prototype_properties,
njs_nitems(njs_async_prototype_properties),
};
const njs_object_type_init_t njs_async_function_type_init = {
.constructor = njs_native_ctor(njs_function_constructor, 1, 1),
.constructor_props = &njs_async_constructor_init,
.prototype_props = &njs_async_prototype_init,
.prototype_value = { .object = { .type = NJS_OBJECT } },
};
const njs_object_prop_t njs_async_function_instance_properties[] =
{
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("length"),
.value = njs_prop_handler(njs_function_instance_length),
.configurable = 1,
},
};
const njs_object_init_t njs_async_function_instance_init = {
njs_async_function_instance_properties,
njs_nitems(njs_async_function_instance_properties),
};