njs_generate_return_statement_end(njs_vm_t *vm, njs_generator_t *generator,
    njs_parser_node_t *node)
{
    njs_index_t              index;
    const njs_str_t          *dest;
    njs_vmcode_return_t      *code;
    njs_generator_patch_t    *patch;
    njs_generator_block_t    *block, *immediate, *top;
    njs_vmcode_try_return_t  *try_return;

    if (node->right != NULL) {
        index = node->right->index;

    } else {
        index = njs_scope_global_index(vm, &njs_value_undefined,
                                       generator->runtime);
    }

    if (njs_slow_path(index == NJS_INDEX_ERROR)) {
        return NJS_ERROR;
    }

    immediate = njs_generate_lookup_block(generator->block, NJS_GENERATOR_TRY,
                                          &no_label);

    njs_debug_generator(vm, "LOOKUP TRY   %p", immediate);

    if (njs_fast_path(immediate == NULL)) {
        njs_generate_code(generator, njs_vmcode_return_t, code,
                          NJS_VMCODE_RETURN, 1, node);
        code->retval = index;
        node->index = index;

        return njs_generator_stack_pop(vm, generator, NULL);
    }

    if (immediate->type == NJS_GENERATOR_TRY && immediate->exit != NULL) {
        dest = njs_generate_jump_destination(vm, immediate->next,
                                             "break/return",
                                             NJS_GENERATOR_ALL,
                                             &immediate->exit->label,
                                             &return_label);
        if (njs_slow_path(dest == NULL)) {
            return NJS_ERROR;
        }
    }

    top = immediate;
    block = immediate->next;

    while (block != NULL) {
        if (block->type & NJS_GENERATOR_TRY) {
            top = block;
        }

        block = block->next;
    }

    njs_generate_code(generator, njs_vmcode_try_return_t, try_return,
                      NJS_VMCODE_TRY_RETURN, 2, node);
    try_return->retval = index;
    try_return->save = top->index;
    try_return->offset = offsetof(njs_vmcode_try_return_t, offset);

    patch = njs_generate_make_exit_patch(vm, immediate, &return_label,
                                         njs_code_offset(generator, try_return)
                                         + offsetof(njs_vmcode_try_return_t,
                                                    offset));
    if (njs_slow_path(patch == NULL)) {
        return NJS_ERROR;
    }

    return njs_generator_stack_pop(vm, generator, NULL);
}
njs_generate_return_statement_end(njs_vm_t *vm, njs_generator_t *generator,
    njs_parser_node_t *node)
{
    njs_index_t              index;
    const njs_str_t          *dest;
    njs_vmcode_return_t      *code;
    njs_generator_patch_t    *patch;
    njs_generator_block_t    *block, *immediate, *top;
    njs_vmcode_try_return_t  *try_return;

    if (node->right != NULL) {
        index = node->right->index;

    } else {
        index = njs_scope_global_index(vm, &njs_value_undefined,
                                       generator->runtime);
    }

    if (njs_slow_path(index == NJS_INDEX_ERROR)) {
        return NJS_ERROR;
    }

    immediate = njs_generate_lookup_block(generator->block, NJS_GENERATOR_TRY,
                                          &no_label);

    njs_debug_generator(vm, "LOOKUP TRY   %p", immediate);

    if (njs_fast_path(immediate == NULL)) {
        njs_generate_code(generator, njs_vmcode_return_t, code,
                          NJS_VMCODE_RETURN, 1, node);
        code->retval = index;
        node->index = index;

        return njs_generator_stack_pop(vm, generator, NULL);
    }

    if (immediate->type == NJS_GENERATOR_TRY && immediate->exit != NULL) {
        dest = njs_generate_jump_destination(vm, immediate->next,
                                             "break/return",
                                             NJS_GENERATOR_ALL,
                                             &immediate->exit->label,
                                             &return_label);
        if (njs_slow_path(dest == NULL)) {
            return NJS_ERROR;
        }
    }

    top = immediate;
    block = immediate->next;

    while (block != NULL) {
        if (block->type & NJS_GENERATOR_TRY) {
            top = block;
        }

        block = block->next;
    }

    njs_generate_code(generator, njs_vmcode_try_return_t, try_return,
                      NJS_VMCODE_TRY_RETURN, 2, node);
    try_return->retval = index;
    try_return->save = top->index;
    try_return->offset = offsetof(njs_vmcode_try_return_t, offset);

    patch = njs_generate_make_exit_patch(vm, immediate, &return_label,
                                         njs_code_offset(generator, try_return)
                                         + offsetof(njs_vmcode_try_return_t,
                                                    offset));
    if (njs_slow_path(patch == NULL)) {
        return NJS_ERROR;
    }

    return njs_generator_stack_pop(vm, generator, NULL);
}