[njs] Refactored bound function calls according to the spec.

Dmitry Volyntsev xeioex at nginx.com
Tue Oct 11 02:35:14 UTC 2022


details:   https://hg.nginx.org/njs/rev/e4297a78844e
branches:  
changeset: 1976:e4297a78844e
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Mon Oct 10 18:45:09 2022 -0700
description:
Refactored bound function calls according to the spec.

This fixes #533, #546, #579 issues on Github.

diffstat:

 src/njs_disassembler.c   |   14 +---
 src/njs_error.c          |    9 +-
 src/njs_extern.c         |    1 -
 src/njs_function.c       |  171 ++++++++++++++++++++--------------------------
 src/njs_function.h       |    5 +-
 src/njs_generator.c      |   10 +-
 src/njs_promise.c        |    1 -
 src/njs_value.h          |    6 +-
 src/njs_vm.c             |    1 -
 src/njs_vmcode.c         |   63 +++++++++++-----
 src/njs_vmcode.h         |    9 +--
 src/test/njs_unit_test.c |   18 +++-
 test/js/async_bind.t.js  |   13 +++
 13 files changed, 161 insertions(+), 160 deletions(-)

diffs (735 lines):

diff -r 16442fa970ee -r e4297a78844e src/njs_disassembler.c
--- a/src/njs_disassembler.c	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/njs_disassembler.c	Mon Oct 10 18:45:09 2022 -0700
@@ -17,6 +17,8 @@ typedef struct {
 
 static njs_code_name_t  code_names[] = {
 
+    { NJS_VMCODE_PUT_ARG, sizeof(njs_vmcode_1addr_t),
+          njs_str("PUT ARG         ") },
     { NJS_VMCODE_OBJECT, sizeof(njs_vmcode_object_t),
           njs_str("OBJECT          ") },
     { NJS_VMCODE_FUNCTION, sizeof(njs_vmcode_function_t),
@@ -204,7 +206,6 @@ njs_disassemble(u_char *start, u_char *e
     njs_vmcode_import_t          *import;
     njs_vmcode_finally_t         *finally;
     njs_vmcode_try_end_t         *try_end;
-    njs_vmcode_move_arg_t        *move_arg;
     njs_vmcode_try_start_t       *try_start;
     njs_vmcode_operation_t       operation;
     njs_vmcode_cond_jump_t       *cond_jump;
@@ -513,17 +514,6 @@ njs_disassemble(u_char *start, u_char *e
             continue;
         }
 
-        if (operation == NJS_VMCODE_MOVE_ARG) {
-            move_arg = (njs_vmcode_move_arg_t *) p;
-
-            njs_printf("%5uD | %05uz MOVE ARGUMENT     %uD %04Xz\n",
-                       line, p - start, move_arg->dst, (size_t) move_arg->src);
-
-            p += sizeof(njs_vmcode_move_arg_t);
-
-            continue;
-        }
-
         code_name = code_names;
         n = njs_nitems(code_names);
 
diff -r 16442fa970ee -r e4297a78844e src/njs_error.c
--- a/src/njs_error.c	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/njs_error.c	Mon Oct 10 18:45:09 2022 -0700
@@ -1292,6 +1292,11 @@ njs_add_backtrace_entry(njs_vm_t *vm, nj
 
     function = native_frame->function;
 
+    if (function != NULL && function->bound != NULL) {
+        /* Skip. */
+        return NJS_OK;
+    }
+
     be = njs_arr_add(stack);
     if (njs_slow_path(be == NULL)) {
         return NJS_ERROR;
@@ -1301,10 +1306,6 @@ njs_add_backtrace_entry(njs_vm_t *vm, nj
     be->file = njs_str_value("");
 
     if (function != NULL && function->native) {
-        while (function->bound != NULL) {
-            function = function->u.bound_target;
-        }
-
         ret = njs_builtin_match_native_function(vm, function, &be->name);
         if (ret == NJS_OK) {
             return NJS_OK;
diff -r 16442fa970ee -r e4297a78844e src/njs_extern.c
--- a/src/njs_extern.c	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/njs_extern.c	Mon Oct 10 18:45:09 2022 -0700
@@ -77,7 +77,6 @@ njs_external_add(njs_vm_t *vm, njs_arr_t
             function->object.type = NJS_FUNCTION;
             function->object.shared = 1;
             function->object.extensible = 1;
-            function->args_offset = 1;
             function->native = 1;
             function->u.native = external->u.method.native;
             function->magic8 = external->u.method.magic8;
diff -r 16442fa970ee -r e4297a78844e src/njs_function.c
--- a/src/njs_function.c	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/njs_function.c	Mon Oct 10 18:45:09 2022 -0700
@@ -30,7 +30,6 @@ njs_function_alloc(njs_vm_t *vm, njs_fun
      */
 
     function->ctor = lambda->ctor;
-    function->args_offset = 1;
     function->u.lambda = lambda;
 
     if (function->ctor) {
@@ -77,7 +76,6 @@ njs_vm_function_alloc(njs_vm_t *vm, njs_
     }
 
     function->native = 1;
-    function->args_offset = 1;
     function->u.native = native;
 
     return function;
@@ -376,12 +374,10 @@ njs_function_native_frame(njs_vm_t *vm, 
     njs_bool_t ctor)
 {
     size_t              size;
-    njs_uint_t          n;
-    njs_value_t         *value, *bound;
+    njs_value_t         *value;
     njs_native_frame_t  *frame;
 
-    size = NJS_NATIVE_FRAME_SIZE
-           + (function->args_offset + nargs) * sizeof(njs_value_t);
+    size = NJS_NATIVE_FRAME_SIZE + (1 /* this */ + nargs) * sizeof(njs_value_t);
 
     frame = njs_function_frame_alloc(vm, size);
     if (njs_slow_path(frame == NULL)) {
@@ -389,31 +385,16 @@ njs_function_native_frame(njs_vm_t *vm, 
     }
 
     frame->function = function;
-    frame->nargs = function->args_offset + nargs;
+    frame->nargs = nargs;
     frame->ctor = ctor;
     frame->native = 1;
     frame->pc = NULL;
 
     value = (njs_value_t *) ((u_char *) frame + NJS_NATIVE_FRAME_SIZE);
 
-    frame->arguments = value;
-    frame->arguments_offset = value + function->args_offset;
-
-    bound = function->bound;
-
-    if (bound == NULL) {
-        /* GC: njs_retain(this); */
-        *value++ = *this;
+    njs_value_assign(value++, this++);
 
-    } else {
-        n = function->args_offset;
-
-        do {
-            /* GC: njs_retain(bound); */
-            *value++ = *bound++;
-            n--;
-        } while (n != 0);
-    }
+    frame->arguments = value;
 
     if (args != NULL) {
         memcpy(value, args, nargs * sizeof(njs_value_t));
@@ -430,37 +411,15 @@ njs_function_lambda_frame(njs_vm_t *vm, 
 {
     size_t                 n, frame_size;
     uint32_t               args_count, value_count, value_size;
-    njs_value_t            *value, *bound, **new;
+    njs_value_t            *value, **new;
     njs_frame_t            *frame;
-    njs_function_t         *target;
     njs_native_frame_t     *native_frame;
     njs_function_lambda_t  *lambda;
 
-    bound = function->bound;
-
-    if (njs_fast_path(bound == NULL)) {
-        lambda = function->u.lambda;
-        target = function;
-
-    } else {
-        target = function->u.bound_target;
-
-        if (njs_slow_path(target->bound != NULL)) {
+    lambda = function->u.lambda;
 
-            /*
-             * FIXME: bound functions should call target function with
-             * bound "this" and bound args.
-             */
-
-            njs_internal_error(vm, "chain of bound function are not supported");
-            return NJS_ERROR;
-        }
-
-        lambda = target->u.lambda;
-    }
-
-    args_count = function->args_offset + njs_max(nargs, lambda->nargs);
-    value_count = args_count + njs_max(args_count, lambda->nlocal);
+    args_count = njs_max(nargs, lambda->nargs);
+    value_count = args_count + lambda->nlocal;
 
     value_size = value_count * sizeof(njs_value_t *);
 
@@ -485,9 +444,8 @@ njs_function_lambda_frame(njs_vm_t *vm, 
     }
 
     native_frame->arguments = value;
-    native_frame->arguments_offset = value + (function->args_offset - 1);
     native_frame->local = new + args_count;
-    native_frame->function = target;
+    native_frame->function = function;
     native_frame->nargs = nargs;
     native_frame->ctor = ctor;
     native_frame->native = 0;
@@ -502,28 +460,11 @@ njs_function_lambda_frame(njs_vm_t *vm, 
         njs_set_object(native_frame->local[0], &vm->global_object);
     }
 
-    if (bound != NULL) {
-        n = function->args_offset;
-        native_frame->nargs += n - 1;
-
-        if (!ctor) {
-            *native_frame->local[0] = *bound;
-        }
-
-        bound++;
-        n--;
-
-        while (n != 0) {
-            *value++ = *bound++;
-            n--;
-        };
-    }
-
     /* Copy arguments. */
 
     if (args != NULL) {
         while (nargs != 0) {
-            *value++ = *args++;
+            njs_value_assign(value++, args++);
             nargs--;
         }
     }
@@ -624,7 +565,7 @@ njs_function_lambda_call(njs_vm_t *vm, v
     lambda = function->u.lambda;
 
     args = vm->top_frame->arguments;
-    local = vm->top_frame->local + function->args_offset;
+    local = vm->top_frame->local + 1 /* this */;
 
     /* Move all arguments. */
 
@@ -702,7 +643,7 @@ njs_int_t
 njs_function_native_call(njs_vm_t *vm)
 {
     njs_int_t              ret;
-    njs_function_t         *function, *target;
+    njs_function_t         *function;
     njs_native_frame_t     *native, *previous;
     njs_function_native_t  call;
 
@@ -723,21 +664,10 @@ njs_function_native_call(njs_vm_t *vm)
     }
 #endif
 
-    if (njs_fast_path(function->bound == NULL)) {
-        call = function->u.native;
-
-    } else {
-        target = function->u.bound_target;
+    call = function->u.native;
 
-        if (njs_slow_path(target->bound != NULL)) {
-            njs_internal_error(vm, "chain of bound function are not supported");
-            return NJS_ERROR;
-        }
-
-        call = target->u.native;
-    }
-
-    ret = call(vm, native->arguments, native->nargs, function->magic8);
+    ret = call(vm, &native->arguments[-1], 1 /* this */ + native->nargs,
+               function->magic8);
 
 #ifdef NJS_DEBUG_OPCODE
     if (vm->options.opcode_debug) {
@@ -833,14 +763,13 @@ njs_function_frame_save(njs_vm_t *vm, nj
     function = active->function;
     lambda = function->u.lambda;
 
-    args_count = function->args_offset + njs_max(native->nargs, lambda->nargs);
-    value_count = args_count + njs_max(args_count, lambda->nlocal);
+    args_count = njs_max(native->nargs, lambda->nargs);
+    value_count = args_count + lambda->nlocal;
 
     new = (njs_value_t **) ((u_char *) native + NJS_FRAME_SIZE);
     value = (njs_value_t *) (new + value_count);
 
     native->arguments = value;
-    native->arguments_offset = value + (function->args_offset - 1);
     native->local = new + njs_function_frame_args_count(active);
     native->pc = pc;
 
@@ -848,14 +777,14 @@ njs_function_frame_save(njs_vm_t *vm, nj
     p = native->arguments;
 
     while (start < end) {
-        *p = *start++;
+        njs_value_assign(p, start++);
         *new++ = p++;
     }
 
     /* Move all arguments. */
 
     p = native->arguments;
-    local = native->local + function->args_offset;
+    local = native->local + 1 /* this */;
 
     for (n = 0; n < function->args_count; n++) {
         if (!njs_is_valid(p)) {
@@ -1461,11 +1390,54 @@ activate:
 
 
 static njs_int_t
+njs_function_bound_call(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
+{
+    u_char          *p;
+    njs_int_t       ret;
+    size_t          args_count;
+    njs_value_t     *arguments;
+    njs_function_t  *function, *bound;
+
+    function = vm->top_frame->function;
+    bound = function->context;
+
+    njs_assert(bound != NULL);
+
+    args_count = 1 /* this */ + function->bound_args;
+
+    if (nargs == 1) {
+        return njs_function_apply(vm, bound, function->bound, args_count,
+                                 &vm->retval);
+    }
+
+    arguments = njs_mp_alloc(vm->mem_pool,
+                             (args_count + nargs - 1) * sizeof(njs_value_t));
+    if (njs_slow_path(arguments == NULL)) {
+        njs_memory_error(vm);
+        return NJS_ERROR;
+    }
+
+    p = njs_cpymem(arguments, function->bound,
+                   args_count * sizeof(njs_value_t));
+    memcpy(p, &args[1], (nargs - 1) * sizeof(njs_value_t));
+
+    ret = njs_function_apply(vm, bound, arguments, args_count + nargs - 1,
+                             &vm->retval);
+
+    njs_mp_free(vm->mem_pool, arguments);
+
+    return ret;
+}
+
+
+static njs_int_t
 njs_function_prototype_bind(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
     size_t          size;
     njs_int_t       ret;
+    njs_uint_t      bound_args;
     njs_value_t     *values, name;
     njs_function_t  *function;
 
@@ -1481,6 +1453,8 @@ njs_function_prototype_bind(njs_vm_t *vm
     }
 
     *function = *njs_function(&args[0]);
+    function->native = 1;
+    function->u.native = njs_function_bound_call;
 
     njs_lvlhsh_init(&function->object.hash);
 
@@ -1490,7 +1464,7 @@ njs_function_prototype_bind(njs_vm_t *vm
     function->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object;
     function->object.shared = 0;
 
-    function->u.bound_target = njs_function(&args[0]);
+    function->context = njs_function(&args[0]);
 
     ret = njs_value_property(vm, &args[0], njs_value_arg(&njs_string_name),
                              &name);
@@ -1509,21 +1483,23 @@ njs_function_prototype_bind(njs_vm_t *vm
 
     if (nargs == 1) {
         args = njs_value_arg(&njs_value_undefined);
+        bound_args = 0;
 
     } else {
-        nargs--;
         args++;
+        bound_args = nargs - 2;
     }
 
-    if (nargs > function->args_count) {
+    if (bound_args > function->args_count) {
         function->args_count = 0;
 
     } else {
-        function->args_count -= nargs - 1;
+        function->args_count -= bound_args;
     }
 
-    function->args_offset = nargs;
-    size = nargs * sizeof(njs_value_t);
+    function->bound_args = bound_args;
+
+    size = (1 /* this */ + bound_args) * sizeof(njs_value_t);
 
     values = njs_mp_alloc(vm->mem_pool, size);
     if (njs_slow_path(values == NULL)) {
@@ -1700,7 +1676,6 @@ const njs_object_type_init_t  njs_functi
    .constructor_props = &njs_function_constructor_init,
    .prototype_props = &njs_function_prototype_init,
    .prototype_value = { .function = { .native = 1,
-                                      .args_offset = 1,
                                       .u.native = njs_prototype_function,
                                       .object = { .type = NJS_FUNCTION } } },
 };
diff -r 16442fa970ee -r e4297a78844e src/njs_function.h
--- a/src/njs_function.h	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/njs_function.h	Mon Oct 10 18:45:09 2022 -0700
@@ -47,9 +47,9 @@ struct njs_native_frame_s {
     njs_function_t                 *function;
     njs_native_frame_t             *previous;
 
+    /* Points to the first arg after 'this'. */
     njs_value_t                    *arguments;
     njs_object_t                   *arguments_object;
-    njs_value_t                    *arguments_offset;
     njs_value_t                    **local;
 
     uint32_t                       size;
@@ -57,7 +57,10 @@ struct njs_native_frame_s {
 
     njs_value_t                    *retval;
 
+    /* Number of allocated args on the frame. */
     uint32_t                       nargs;
+    /* Number of already put args. */
+    uint32_t                       put_args;
 
     uint8_t                        native;            /* 1 bit  */
     /* Function is called as constructor with "new" keyword. */
diff -r 16442fa970ee -r e4297a78844e src/njs_generator.c
--- a/src/njs_generator.c	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/njs_generator.c	Mon Oct 10 18:45:09 2022 -0700
@@ -4382,22 +4382,20 @@ njs_generate_move_arguments(njs_vm_t *vm
     njs_parser_node_t *node)
 {
     njs_jump_off_t               func_offset;
-    njs_vmcode_move_arg_t        *move_arg;
+    njs_vmcode_1addr_t           *put_arg;
     njs_vmcode_function_frame_t  *func;
 
     if (node == NULL) {
         return njs_generator_stack_pop(vm, generator, generator->context);
     }
 
-    njs_generate_code(generator, njs_vmcode_move_arg_t, move_arg,
-                      NJS_VMCODE_MOVE_ARG, 0, node);
-    move_arg->src = node->left->index;
+    njs_generate_code(generator, njs_vmcode_1addr_t, put_arg,
+                      NJS_VMCODE_PUT_ARG, 0, node);
+    put_arg->index = node->left->index;
 
     func_offset = *((njs_jump_off_t *) generator->context);
     func = njs_code_ptr(generator, njs_vmcode_function_frame_t, func_offset);
 
-    move_arg->dst = (njs_uint_t) func->nargs;
-
     func->nargs++;
 
     if (node->right == NULL) {
diff -r 16442fa970ee -r e4297a78844e src/njs_promise.c
--- a/src/njs_promise.c	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/njs_promise.c	Mon Oct 10 18:45:09 2022 -0700
@@ -255,7 +255,6 @@ njs_promise_create_function(njs_vm_t *vm
     function->object.shared_hash = vm->shared->arrow_instance_hash;
     function->object.type = NJS_FUNCTION;
     function->object.extensible = 1;
-    function->args_offset = 1;
     function->native = 1;
     function->context = context;
 
diff -r 16442fa970ee -r e4297a78844e src/njs_value.h
--- a/src/njs_value.h	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/njs_value.h	Mon Oct 10 18:45:09 2022 -0700
@@ -250,7 +250,8 @@ struct njs_typed_array_s {
 struct njs_function_s {
     njs_object_t                      object;
 
-    uint8_t                           args_offset;
+    /* Number of bound args excluding 'this'. */
+    uint8_t                           bound_args;
 
     uint8_t                           args_count:4;
 
@@ -265,11 +266,11 @@ struct njs_function_s {
     union {
         njs_function_lambda_t         *lambda;
         njs_function_native_t         native;
-        njs_function_t                *bound_target;
     } u;
 
     void                              *context;
 
+    /* Bound args including 'this'. */
     njs_value_t                       *bound;
 };
 
@@ -428,7 +429,6 @@ typedef struct {
     .magic8 = _magic,                                                         \
     .args_count = _args_count,                                                \
     .ctor = _ctor,                                                            \
-    .args_offset = 1,                                                         \
     .u.native = _function,                                                    \
     .object = { .type = NJS_FUNCTION,                                         \
                 .shared = 1,                                                  \
diff -r 16442fa970ee -r e4297a78844e src/njs_vm.c
--- a/src/njs_vm.c	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/njs_vm.c	Mon Oct 10 18:45:09 2022 -0700
@@ -300,7 +300,6 @@ njs_vm_compile_module(njs_vm_t *vm, njs_
     lambda->declarations = (arr != NULL) ? arr->start : NULL;
     lambda->ndeclarations = (arr != NULL) ? arr->items : 0;
 
-    module->function.args_offset = 1;
     module->function.u.lambda = lambda;
 
     return module;
diff -r 16442fa970ee -r e4297a78844e src/njs_vmcode.c
--- a/src/njs_vmcode.c	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/njs_vmcode.c	Mon Oct 10 18:45:09 2022 -0700
@@ -98,6 +98,7 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_c
     njs_value_t                  numeric1, numeric2, primitive1, primitive2;
     njs_frame_t                  *frame;
     njs_jump_off_t               ret;
+    njs_vmcode_1addr_t           *put_arg;
     njs_vmcode_await_t           *await;
     njs_native_frame_t           *previous, *native;
     njs_property_next_t          *next;
@@ -105,7 +106,6 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_c
     njs_vmcode_finally_t         *finally;
     njs_vmcode_generic_t         *vmcode;
     njs_vmcode_variable_t        *var;
-    njs_vmcode_move_arg_t        *move_arg;
     njs_vmcode_prop_get_t        *get;
     njs_vmcode_prop_set_t        *set;
     njs_vmcode_operation_t       op;
@@ -657,18 +657,16 @@ next:
         } else {
 
             switch (op) {
-            case NJS_VMCODE_MOVE_ARG:
-                move_arg = (njs_vmcode_move_arg_t *) pc;
+            case NJS_VMCODE_PUT_ARG:
+                put_arg = (njs_vmcode_1addr_t *) pc;
                 native = vm->top_frame;
 
-                hint = move_arg->dst;
-
-                value1 = &native->arguments_offset[hint];
-                njs_vmcode_operand(vm, move_arg->src, value2);
-
-                *value1 = *value2;
-
-                ret = sizeof(njs_vmcode_move_arg_t);
+                value1 = &native->arguments[native->put_args++];
+                njs_vmcode_operand(vm, put_arg->index, value2);
+
+                njs_value_assign(value1, value2);
+
+                ret = sizeof(njs_vmcode_1addr_t);
                 break;
 
             case NJS_VMCODE_STOP:
@@ -1290,7 +1288,6 @@ njs_vmcode_template_literal(njs_vm_t *vm
 
     static const njs_function_t  concat = {
           .native = 1,
-          .args_offset = 1,
           .u.native = njs_string_prototype_concat
     };
 
@@ -1584,7 +1581,7 @@ njs_vmcode_instance_of(njs_vm_t *vm, njs
     function = njs_function(constructor);
 
     if (function->bound != NULL) {
-        function = function->u.bound_target;
+        function = function->context;
         njs_set_function(&bound, function);
         constructor = &bound;
     }
@@ -1849,33 +1846,57 @@ static njs_jump_off_t
 njs_function_frame_create(njs_vm_t *vm, njs_value_t *value,
     const njs_value_t *this, uintptr_t nargs, njs_bool_t ctor)
 {
-    njs_value_t     val;
+    njs_int_t       ret;
+    njs_value_t     new_target, *args;
     njs_object_t    *object;
-    njs_function_t  *function;
+    njs_function_t  *function, *target;
 
     if (njs_fast_path(njs_is_function(value))) {
 
         function = njs_function(value);
+        target = function;
+        args = NULL;
 
         if (ctor) {
-            if (!function->ctor) {
+            if (function->bound != NULL) {
+                target = function->context;
+                nargs += function->bound_args;
+
+                args = njs_mp_alloc(vm->mem_pool, nargs * sizeof(njs_value_t));
+                if (njs_slow_path(args == NULL)) {
+                    njs_memory_error(vm);
+                    return NJS_ERROR;
+                }
+
+                memcpy(args, &function->bound[1],
+                       function->bound_args * sizeof(njs_value_t));
+            }
+
+            if (!target->ctor) {
                 njs_type_error(vm, "%s is not a constructor",
                                njs_type_string(value->type));
                 return NJS_ERROR;
             }
 
-            if (!function->native) {
+            if (!target->native) {
                 object = njs_function_new_object(vm, value);
                 if (njs_slow_path(object == NULL)) {
                     return NJS_ERROR;
                 }
 
-                njs_set_object(&val, object);
-                this = &val;
+                njs_set_object(&new_target, object);
+                this = &new_target;
             }
         }
 
-        return njs_function_frame(vm, function, this, NULL, nargs, ctor);
+        ret = njs_function_frame(vm, target, this, args, nargs, ctor);
+
+        if (args != NULL) {
+            vm->top_frame->put_args = function->bound_args;
+            njs_mp_free(vm->mem_pool, args);
+        }
+
+        return ret;
     }
 
     njs_type_error(vm, "%s is not a function", njs_type_string(value->type));
@@ -1902,7 +1923,7 @@ njs_function_new_object(njs_vm_t *vm, nj
     function = njs_function(constructor);
 
     if (function->bound != NULL) {
-        function = function->u.bound_target;
+        function = function->context;
         njs_set_function(&bound, function);
         constructor = &bound;
     }
diff -r 16442fa970ee -r e4297a78844e src/njs_vmcode.h
--- a/src/njs_vmcode.h	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/njs_vmcode.h	Mon Oct 10 18:45:09 2022 -0700
@@ -31,7 +31,7 @@ typedef uint8_t                         
 
 
 enum {
-    NJS_VMCODE_MOVE_ARG = 0,
+    NJS_VMCODE_PUT_ARG = 0,
     NJS_VMCODE_STOP,
     NJS_VMCODE_JUMP,
     NJS_VMCODE_PROPERTY_SET,
@@ -411,13 +411,6 @@ typedef struct {
 
 typedef struct {
     njs_vmcode_t               code;
-    njs_index_t                src;
-    njs_uint_t                 dst;
-} njs_vmcode_move_arg_t;
-
-
-typedef struct {
-    njs_vmcode_t               code;
     njs_value_t                *function;
     njs_index_t                retval;
 } njs_vmcode_function_copy_t;
diff -r 16442fa970ee -r e4297a78844e src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Thu Oct 06 18:28:52 2022 -0700
+++ b/src/test/njs_unit_test.c	Mon Oct 10 18:45:09 2022 -0700
@@ -7818,12 +7818,22 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("var bArray = Array.bind(null, 10); new bArray(16)"),
       njs_str("10,16") },
 
-#if 0 /* FIXME: refactor Bound calls (9.4.1.1[[Call]]). */
     { njs_str("function f(x,y) {return {args:arguments,length:arguments.length}};"
-              "var bf = f.bind({}, 'a'); var bbf = bf.bind({},'b'); var o = bbf('c');"),
-              "[o.args[0], o.args[2], o.length]"
+              "var bf = f.bind({}, 'a'); var bbf = bf.bind({},'b'); var o = bbf('c');"
+              "[o.args[0], o.args[2], o.length]"),
       njs_str("a,c,3") },
-#endif
+
+    { njs_str("var f = function (a, b) {return [this, a, b]};"
+              "var b1 = f.bind('THIS', 'x');"
+              "var b2 = b1.bind('WAKA', 'y');"
+              "njs.dump([f(2,3), b1(3), b2()])"),
+      njs_str("[[undefined,2,3],['THIS','x',3],['THIS','x','y']]") },
+
+    { njs_str("var f = Math.max;"
+              "var b1 = f.bind('THIS', 4);"
+              "var b2 = b1.bind('WAKA', 5);"
+              "njs.dump([f(2,3), b1(3), b2()])"),
+      njs_str("[3,4,5]") },
 
     { njs_str("var s = { toString: function() { return '123' } };"
                  "var a = 'abc'; a.concat('абв', s)"),
diff -r 16442fa970ee -r e4297a78844e test/js/async_bind.t.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/js/async_bind.t.js	Mon Oct 10 18:45:09 2022 -0700
@@ -0,0 +1,13 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+async function f(a1, a2, a3) {
+    var v = await a1;
+    return [a1, a2, a3];
+}
+
+f.bind(null,1,2)('a')
+.then(v => assert.compareArray(v, [1, 2, 'a']))
+.then($DONE, $DONE);


More information about the nginx-devel mailing list