njs_promise_new_capability(njs_vm_t *vm, njs_value_t *constructor)
{
    njs_int_t                 ret;
    njs_value_t               argument, this;
    njs_object_t              *object;
    njs_function_t            *function;
    njs_promise_context_t     *context;
    njs_promise_capability_t  *capability;

    object = NULL;
    function = NULL;

    ret = njs_promise_value_constructor(vm, constructor, constructor);
    if (njs_slow_path(ret != NJS_OK)) {
        return NULL;
    }

    capability = njs_mp_zalloc(vm->mem_pool, sizeof(njs_promise_capability_t));
    if (njs_slow_path(capability == NULL)) {
        njs_memory_error(vm);
        return NULL;
    }

    function = njs_promise_create_function(vm, sizeof(njs_promise_context_t));
    if (njs_slow_path(function == NULL)) {
        return NULL;
    }

    njs_set_undefined(&capability->resolve);
    njs_set_undefined(&capability->reject);

    function->u.native = njs_promise_capability_executor;
    function->args_count = 2;

    context = function->context;
    context->capability = capability;

    njs_set_function(&argument, function);

    object = njs_function_new_object(vm, constructor);
    if (njs_slow_path(object == NULL)) {
        return NULL;
    }

    njs_set_object(&this, object);

    ret = njs_function_call2(vm, njs_function(constructor), &this,
                             &argument, 1, &capability->promise, 1);
    if (njs_slow_path(ret != NJS_OK)) {
        return NULL;
    }

    if (njs_slow_path(!njs_is_function(&capability->resolve))) {
        njs_type_error(vm, "capability resolve slot is not callable");
        return NULL;
    }

    if (njs_slow_path(!njs_is_function(&capability->reject))) {
        njs_type_error(vm, "capability reject slot is not callable");
        return NULL;
    }

    return capability;
}
njs_promise_new_capability(njs_vm_t *vm, njs_value_t *constructor)
{
    njs_int_t                 ret;
    njs_value_t               argument, this;
    njs_object_t              *object;
    njs_function_t            *function;
    njs_promise_context_t     *context;
    njs_promise_capability_t  *capability;

    object = NULL;
    function = NULL;

    ret = njs_promise_value_constructor(vm, constructor, constructor);
    if (njs_slow_path(ret != NJS_OK)) {
        return NULL;
    }

    capability = njs_mp_zalloc(vm->mem_pool, sizeof(njs_promise_capability_t));
    if (njs_slow_path(capability == NULL)) {
        njs_memory_error(vm);
        return NULL;
    }

    function = njs_promise_create_function(vm, sizeof(njs_promise_context_t));
    if (njs_slow_path(function == NULL)) {
        return NULL;
    }

    njs_set_undefined(&capability->resolve);
    njs_set_undefined(&capability->reject);

    function->u.native = njs_promise_capability_executor;
    function->args_count = 2;

    context = function->context;
    context->capability = capability;

    njs_set_function(&argument, function);

    object = njs_function_new_object(vm, constructor);
    if (njs_slow_path(object == NULL)) {
        return NULL;
    }

    njs_set_object(&this, object);

    ret = njs_function_call2(vm, njs_function(constructor), &this,
                             &argument, 1, &capability->promise, 1);
    if (njs_slow_path(ret != NJS_OK)) {
        return NULL;
    }

    if (njs_slow_path(!njs_is_function(&capability->resolve))) {
        njs_type_error(vm, "capability resolve slot is not callable");
        return NULL;
    }

    if (njs_slow_path(!njs_is_function(&capability->reject))) {
        njs_type_error(vm, "capability reject slot is not callable");
        return NULL;
    }

    return capability;
}