]> git.kaiwu.me - njs.git/commitdiff
Functions refactored.
authorIgor Sysoev <igor@sysoev.ru>
Fri, 11 Dec 2015 15:41:00 +0000 (18:41 +0300)
committerIgor Sysoev <igor@sysoev.ru>
Fri, 11 Dec 2015 15:41:00 +0000 (18:41 +0300)
14 files changed:
njs/njs_array.c
njs/njs_builtin.c
njs/njs_disassembler.c
njs/njs_function.c
njs/njs_function.h
njs/njs_generator.c
njs/njs_parser.c
njs/njs_parser.h
njs/njs_parser_expression.c
njs/njs_vm.c
njs/njs_vm.h
njs/njscript.c
njs/njscript.h
njs/test/njs_unit_test.c

index 87d9a3235b83a61eea60c8aa48f6503cedd1b370..51fd43579f436b7410c59a688843c49e7293757e 100644 (file)
@@ -723,7 +723,7 @@ njs_array_prototype_for_each(njs_vm_t *vm, njs_param_t *param)
     each->index = n;
 
     if (n > 0) {
-        vm->current -= sizeof(njs_vmcode_call_t);
+        vm->current -= sizeof(njs_vmcode_function_call_t);
     }
 
     nargs = param->nargs;
@@ -800,7 +800,7 @@ njs_array_prototype_some(njs_vm_t *vm, njs_param_t *param)
 
     func = (nargs != 0) ? &args[0] : (njs_value_t *) &njs_value_void;
 
-    vm->current -= sizeof(njs_vmcode_call_t);
+    vm->current -= sizeof(njs_vmcode_function_call_t);
 
     return njs_function_apply(vm, func, &p);
 }
@@ -866,7 +866,7 @@ njs_array_prototype_every(njs_vm_t *vm, njs_param_t *param)
 
     func = (nargs != 0) ? &args[0] : (njs_value_t *) &njs_value_void;
 
-    vm->current -= sizeof(njs_vmcode_call_t);
+    vm->current -= sizeof(njs_vmcode_function_call_t);
 
     return njs_function_apply(vm, func, &p);
 }
index 9c62757285133139d90b2171cb93fdbfdb426ed2..2a5d0057aea420d8d7621f9eb5f751b3826b10dd 100644 (file)
@@ -94,7 +94,7 @@ njs_builtin_objects_create(njs_vm_t *vm)
     for (i = NJS_FUNCTION_OBJECT; i < NJS_FUNCTION_MAX; i++) {
         functions[i].native = 1;
         functions[i].args_offset = 1;
-        functions[i].code.native = native_functions[i];
+        functions[i].u.native = native_functions[i];
 
         ret = njs_object_hash_create(vm, &functions[i].object.shared_hash,
                                      function_init[i]->properties,
index 8436d0f110496798ddfadb10e9fa81142c51a43b..2bfc9d824d3c135d0e55f6881fffd7924712a83c 100644 (file)
@@ -31,12 +31,12 @@ typedef struct {
 
 static njs_code_name_t  code_names[] = {
 
-    { njs_vmcode_object_create, sizeof(njs_vmcode_object_t),
-          nxt_string("OBJECT CREATE   ") },
-    { njs_vmcode_function_create, sizeof(njs_vmcode_function_create_t),
-          nxt_string("FUNCTION CREATE ") },
-    { njs_vmcode_regexp_create, sizeof(njs_vmcode_regexp_t),
-          nxt_string("REGEXP CREATE   ") },
+    { njs_vmcode_object, sizeof(njs_vmcode_object_t),
+          nxt_string("OBJECT          ") },
+    { njs_vmcode_function, sizeof(njs_vmcode_function_t),
+          nxt_string("FUNCTION        ") },
+    { njs_vmcode_regexp, sizeof(njs_vmcode_regexp_t),
+          nxt_string("REGEXP          ") },
 
     { njs_vmcode_property_get, sizeof(njs_vmcode_prop_get_t),
           nxt_string("PROPERTY GET    ") },
@@ -49,11 +49,11 @@ static njs_code_name_t  code_names[] = {
     { njs_vmcode_instance_of, sizeof(njs_vmcode_instance_of_t),
           nxt_string("INSTANCE OF     ") },
 
-    { njs_vmcode_function, sizeof(njs_vmcode_function_t),
-          nxt_string("FUNCTION        ") },
-    { njs_vmcode_call, sizeof(njs_vmcode_call_t),
-          nxt_string("CALL            ") },
-    { njs_vmcode_return, sizeof(njs_vmcode_stop_t),
+    { njs_vmcode_function_frame, sizeof(njs_vmcode_function_frame_t),
+          nxt_string("FUNCTION FRAME  ") },
+    { njs_vmcode_function_call, sizeof(njs_vmcode_function_call_t),
+          nxt_string("FUNCTION CALL   ") },
+    { njs_vmcode_return, sizeof(njs_vmcode_return_t),
           nxt_string("RETURN          ") },
     { njs_vmcode_stop, sizeof(njs_vmcode_stop_t),
           nxt_string("STOP            ") },
@@ -164,35 +164,35 @@ njs_disassembler(njs_vm_t *vm)
 static void
 njs_disassemble(u_char *start, u_char *end)
 {
-    u_char                   *p;
-    nxt_str_t                *name;
-    nxt_uint_t               n;
-    const char               *sign;
-    njs_code_name_t          *code_name;
-    njs_vmcode_jump_t        *jump;
-    njs_vmcode_1addr_t       *code1;
-    njs_vmcode_2addr_t       *code2;
-    njs_vmcode_3addr_t       *code3;
-    njs_vmcode_array_t       *array;
-    njs_vmcode_catch_t       *catch;
-    njs_vmcode_method_t      *method;
-    njs_vmcode_try_end_t     *try_end;
-    njs_vmcode_try_start_t   *try_start;
-    njs_vmcode_operation_t   operation;
-    njs_vmcode_cond_jump_t   *cond_jump;
-    njs_vmcode_prop_each_t   *each;
-    njs_vmcode_prop_start_t  *prop_start;
+    u_char                     *p;
+    nxt_str_t                  *name;
+    nxt_uint_t                 n;
+    const char                 *sign;
+    njs_code_name_t            *code_name;
+    njs_vmcode_jump_t          *jump;
+    njs_vmcode_1addr_t         *code1;
+    njs_vmcode_2addr_t         *code2;
+    njs_vmcode_3addr_t         *code3;
+    njs_vmcode_array_t         *array;
+    njs_vmcode_catch_t         *catch;
+    njs_vmcode_try_end_t       *try_end;
+    njs_vmcode_try_start_t     *try_start;
+    njs_vmcode_operation_t     operation;
+    njs_vmcode_cond_jump_t     *cond_jump;
+    njs_vmcode_prop_each_t     *each;
+    njs_vmcode_prop_start_t    *prop_start;
+    njs_vmcode_method_frame_t  *method;
 
     p = start;
 
     while (p < end) {
         operation = *(njs_vmcode_operation_t *) p;
 
-        if (operation == njs_vmcode_array_create) {
+        if (operation == njs_vmcode_array) {
             array = (njs_vmcode_array_t *) p;
             p += sizeof(njs_vmcode_array_t);
 
-            printf("ARRAY CREATE      %04lX %ld\n",
+            printf("ARRAY             %04lX %ld\n",
                    array->retval, array->length);
 
             continue;
@@ -230,11 +230,11 @@ njs_disassemble(u_char *start, u_char *end)
             continue;
         }
 
-        if (operation == njs_vmcode_method) {
-            method = (njs_vmcode_method_t *) p;
-            p += sizeof(njs_vmcode_method_t);
+        if (operation == njs_vmcode_method_frame) {
+            method = (njs_vmcode_method_frame_t *) p;
+            p += sizeof(njs_vmcode_method_frame_t);
 
-            printf("METHOD            %04lX %04lX %04lX %d\n", method->function,
+            printf("METHOD FRAME      %04lX %04lX %d\n",
                    method->object, method->method, method->code.nargs);
 
             continue;
index 2ec1856ef10ba10c57c5d0b22660ff4c31d61c39..bca792cb5c6bee2f9bf00b29242f3fce740cb27e 100644 (file)
 #include <string.h>
 
 
-static const njs_vmcode_1addr_t  njs_trap_strings[] = {
-    { .code = { .operation = njs_vmcode_string_primitive,
-                .operands =  NJS_VMCODE_1OPERAND,
-                .retval = NJS_VMCODE_NO_RETVAL },
-      .index = 0 },
-    { .code = { .operation = njs_vmcode_string_primitive,
-                .operands =  NJS_VMCODE_1OPERAND,
-                .retval = NJS_VMCODE_NO_RETVAL },
-      .index = 1 },
-    { .code = { .operation = njs_vmcode_restart,
-                .operands =  NJS_VMCODE_NO_OPERAND,
-                .retval = NJS_VMCODE_NO_RETVAL } },
-};
-
-
-static const njs_vmcode_1addr_t  njs_trap_numbers[] = {
-    { .code = { .operation = njs_vmcode_number_primitive,
-                .operands =  NJS_VMCODE_1OPERAND,
-                .retval = NJS_VMCODE_NO_RETVAL },
-      .index = 0 },
-    { .code = { .operation = njs_vmcode_number_primitive,
-                .operands =  NJS_VMCODE_1OPERAND,
-                .retval = NJS_VMCODE_NO_RETVAL },
-      .index = 1 },
-    { .code = { .operation = njs_vmcode_restart,
-                .operands =  NJS_VMCODE_NO_OPERAND,
-                .retval = NJS_VMCODE_NO_RETVAL } },
-};
-
-
-static const njs_vmcode_1addr_t  njs_trap_number[] = {
-    { .code = { .operation = njs_vmcode_number_primitive,
-                .operands =  NJS_VMCODE_1OPERAND,
-                .retval = NJS_VMCODE_NO_RETVAL },
-      .index = 0 },
-    { .code = { .operation = njs_vmcode_restart,
-                .operands =  NJS_VMCODE_NO_OPERAND,
-                .retval = NJS_VMCODE_NO_RETVAL } },
-};
-
-
-static const njs_vm_trap_t  njs_vm_traps[] = {
-    /* NJS_TRAP_PROPERTY */  { &njs_trap_strings[1], 0 },
-    /* NJS_TRAP_STRINGS */   { &njs_trap_strings[0], 0 },
-    /* NJS_TRAP_INCDEC */    { &njs_trap_numbers[1], 1 },
-    /* NJS_TRAP_NUMBERS */   { &njs_trap_numbers[0], 0 },
-    /* NJS_TRAP_NUMBER */    { &njs_trap_number[0],  0 },
-};
-
-
 njs_function_t *
 njs_function_alloc(njs_vm_t *vm)
 {
-    njs_function_t         *func;
-    njs_function_script_t  *script;
+    njs_function_t  *function;
 
-    func = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_function_t));
+    function = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_function_t));
 
-    if (nxt_fast_path(func != NULL)) {
-        func->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION];
-        func->args_offset = 1;
+    if (nxt_fast_path(function != NULL)) {
+        function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION];
+        function->args_offset = 1;
 
-        script = nxt_mem_cache_zalloc(vm->mem_cache_pool,
-                                      sizeof(njs_function_script_t));
-        if (nxt_slow_path(script == NULL)) {
+        function->u.lambda = nxt_mem_cache_zalloc(vm->mem_cache_pool,
+                                                 sizeof(njs_function_lambda_t));
+        if (nxt_slow_path(function->u.lambda == NULL)) {
             return NULL;
         }
-
-        func->code.script = script;
     }
 
-    return func;
+    return function;
 }
 
 
-nxt_noinline njs_value_t *
-njs_vmcode_native_frame(njs_vm_t *vm, njs_value_t *method, uintptr_t nargs,
-    nxt_bool_t ctor)
+njs_value_t *
+njs_function_native_frame(njs_vm_t *vm, njs_native_t native, size_t local_size,
+    njs_vmcode_t *code)
 {
-    size_t              size, spare_size;
+    size_t              size;
     njs_value_t         *this;
     njs_native_frame_t  *frame;
 
-    size = NJS_NATIVE_FRAME_SIZE
-           + method->data.string_size
-           + nargs * sizeof(njs_value_t);
-
-    if (nxt_fast_path(size <= vm->frame->size)) {
-        frame = (njs_native_frame_t *) vm->frame->last;
-        frame->size = vm->frame->size - size;
-        frame->start = 0;
+    size = NJS_NATIVE_FRAME_SIZE + local_size
+           + code->nargs * sizeof(njs_value_t);
 
-    } else {
-        spare_size = size + NJS_FRAME_SPARE_SIZE;
-        spare_size = nxt_align_size(spare_size, NJS_FRAME_SPARE_SIZE);
-
-        frame = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t),
-                                    spare_size);
-        if (nxt_slow_path(frame == NULL)) {
-            return NULL;
-        }
-
-        frame->size = spare_size - size;
-        frame->start = 1;
+    frame = njs_function_frame_alloc(vm, size);
+    if (nxt_slow_path(frame == NULL)) {
+        return NULL;
     }
 
-    frame->ctor = ctor;
-    frame->reentrant = 0;
-    frame->trap_reference = 0;
-
-    frame->u.exception.next = NULL;
-    frame->u.exception.catch = NULL;
-
-    frame->last = (u_char *) frame + size;
-    frame->previous = vm->frame;
-    vm->frame = frame;
+    frame->u.native = native;
+    frame->native = 1;
+    frame->ctor = code->ctor;
 
-    this = (njs_value_t *)
-               ((u_char *) njs_native_data(frame) + method->data.string_size);
+    this = (njs_value_t *) ((u_char *) njs_native_data(frame) + local_size);
     frame->arguments = this + 1;
     vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = frame->arguments;
 
@@ -145,20 +69,18 @@ njs_vmcode_native_frame(njs_vm_t *vm, njs_value_t *method, uintptr_t nargs,
 }
 
 
-njs_ret_t
-njs_vmcode_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1,
-    njs_value_t *value2)
+nxt_noinline njs_native_frame_t *
+njs_function_frame_alloc(njs_vm_t *vm, size_t size)
 {
-    size_t              size, spare_size;
-    njs_value_t         *values;
+    size_t              spare_size;
     njs_native_frame_t  *frame;
 
-    size = NJS_NATIVE_FRAME_SIZE + 3 * sizeof(njs_value_t);
+    spare_size = vm->frame->free_size;
 
-    if (nxt_fast_path(size <= vm->frame->size)) {
-        frame = (njs_native_frame_t *) vm->frame->last;
-        frame->size = vm->frame->size - size;
-        frame->start = 0;
+    if (nxt_fast_path(size <= spare_size)) {
+        frame = (njs_native_frame_t *) vm->frame->free;
+        frame->first = 0;
+        frame->skip = 0;
 
     } else {
         spare_size = size + NJS_FRAME_SPARE_SIZE;
@@ -167,38 +89,26 @@ njs_vmcode_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1,
         frame = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t),
                                     spare_size);
         if (nxt_slow_path(frame == NULL)) {
-            return NXT_ERROR;
+            return NULL;
         }
 
-        frame->size = spare_size - size;
-        frame->start = 1;
+        frame->first = 1;
+        frame->skip = 0;
     }
 
-    frame->ctor = 0;
-    frame->reentrant = 0;
-
-    values = njs_native_data(frame);
-    njs_set_invalid(&values[0]);
-    values[2] = *value2;
-
-    frame->trap_reference = njs_vm_traps[trap].reference_value;
+    frame->free_size = spare_size - size;
+    frame->free = (u_char *) frame + size;
 
-    if (njs_vm_traps[trap].reference_value) {
-        values[1].data.u.value = value1;
-
-    } else {
-        values[1] = *value1;
-    }
+    frame->reentrant = 0;
+    frame->trap_reference = 0;
 
-    frame->u.exception.catch = NULL;
-    frame->u.restart = vm->current;
-    vm->current = (u_char *) njs_vm_traps[trap].code;
+    frame->exception.next = NULL;
+    frame->exception.catch = NULL;
 
-    frame->last = (u_char *) frame + size;
     frame->previous = vm->frame;
     vm->frame = frame;
 
-    return NXT_OK;
+    return frame;
 }
 
 
@@ -212,23 +122,26 @@ njs_function_constructor(njs_vm_t *vm, njs_param_t *param)
 nxt_noinline njs_ret_t
 njs_function_apply(njs_vm_t *vm, njs_value_t *name, njs_param_t *param)
 {
-    njs_ret_t  ret;
+    njs_ret_t       ret;
+    njs_function_t  *function;
 
     if (njs_is_native(name)) {
         return name->data.u.method(vm, param);
 
     } else if (njs_is_function(name)) {
 
-        if (name->data.u.function->native) {
-            return name->data.u.function->code.native(vm, param);
+        function = name->data.u.function;
+
+        if (function->native) {
+            return function->u.native(vm, param);
         }
 
-        ret = njs_vmcode_function_frame(vm, name, param, 0);
+        ret = njs_function_frame(vm, function, param, 0);
 
         if (nxt_fast_path(ret == NXT_OK)) {
             vm->retval = njs_value_void;
 
-            return njs_function_call(vm, name->data.u.function, param->retval);
+            return njs_function_call(vm, param->retval);
         }
     }
 
@@ -237,58 +150,35 @@ njs_function_apply(njs_vm_t *vm, njs_value_t *name, njs_param_t *param)
 
 
 nxt_noinline njs_ret_t
-njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *name, njs_param_t *param,
+njs_function_frame(njs_vm_t *vm, njs_function_t *function, njs_param_t *param,
     nxt_bool_t ctor)
 {
-    size_t          size, spare_size;
-    uintptr_t       nargs, n;
-    njs_value_t     *args, *arguments;
-    njs_frame_t     *frame;
-    njs_function_t  *func;
+    size_t              size;
+    uintptr_t           nargs, n;
+    njs_value_t         *args, *arguments;
+    njs_frame_t         *frame;
+    njs_native_frame_t  *native_frame;
 
-    func = name->data.u.function;
-    nargs = nxt_max(param->nargs, func->code.script->nargs);
+    nargs = nxt_max(param->nargs, function->u.lambda->nargs);
 
     size = NJS_FRAME_SIZE
            + nargs * sizeof(njs_value_t)
-           + func->code.script->local_size;
-    spare_size = size + func->code.script->spare_size;
-
-    if (spare_size <= vm->frame->size) {
-        frame = (njs_frame_t *) vm->frame->last;
-        frame->native.size = vm->frame->size - size;
-        frame->native.start = 0;
+           + function->u.lambda->local_size;
 
-    } else {
-        if (func->code.script->spare_size != 0) {
-            spare_size = size + NJS_FRAME_SPARE_SIZE;
-            spare_size = nxt_align_size(spare_size, NJS_FRAME_SPARE_SIZE);
-        }
-
-        frame = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t),
-                                    spare_size);
-        if (nxt_slow_path(frame == NULL)) {
-            return NXT_ERROR;
-        }
-
-        frame->native.size = spare_size - size;
-        frame->native.start = 1;
+    native_frame = njs_function_frame_alloc(vm, size);
+    if (nxt_slow_path(native_frame == NULL)) {
+        return NXT_ERROR;
     }
 
-    frame->native.ctor = ctor;
-    frame->native.reentrant = 0;
-    frame->native.trap_reference = 0;
-
-    frame->native.u.exception.next = NULL;
-    frame->native.u.exception.catch = NULL;
+    native_frame->u.function = function;
+    native_frame->native = 0;
+    native_frame->ctor = ctor;
 
-    frame->native.last = (u_char *) frame + size;
-    frame->native.previous = vm->frame;
-    vm->frame = &frame->native;
+    args = (njs_value_t *) ((u_char *) native_frame + NJS_FRAME_SIZE);
+    native_frame->arguments = args + function->args_offset;
+    vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = native_frame->arguments;
 
-    args = (njs_value_t *) ((u_char *) frame + NJS_FRAME_SIZE);
-    frame->native.arguments = args + func->args_offset;
-    vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = frame->native.arguments;
+    frame = (njs_frame_t *) native_frame;
 
     frame->local = &args[nargs];
 
@@ -312,31 +202,30 @@ njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *name, njs_param_t *param,
         nargs--;
     }
 
-    memcpy(frame->local, func->code.script->local_scope,
-           func->code.script->local_size);
-
-    vm->retval = *name;
+    memcpy(frame->local, function->u.lambda->local_scope,
+           function->u.lambda->local_size);
 
     return NXT_OK;
 }
 
 
 nxt_noinline njs_ret_t
-njs_function_call(njs_vm_t *vm, njs_function_t *func, njs_index_t retval)
+njs_function_call(njs_vm_t *vm, njs_index_t retval)
 {
-    njs_frame_t  *frame;
+    njs_frame_t     *frame;
+    njs_function_t  *function;
 
     frame = (njs_frame_t *) vm->frame;
 
     frame->retval = retval;
 
-    frame->return_address = vm->current;
-
-    vm->current = func->code.script->u.code;
+    function = frame->native.u.function;
+    frame->native.u.return_address = vm->current;
+    vm->current = function->u.lambda->u.start;
 
     frame->prev_arguments = vm->scopes[NJS_SCOPE_ARGUMENTS];
     vm->scopes[NJS_SCOPE_ARGUMENTS] = frame->native.arguments
-                                      - func->args_offset;
+                                      - function->args_offset;
 #if (NXT_DEBUG)
     vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = NULL;
 #endif
@@ -375,11 +264,12 @@ const njs_object_init_t  njs_function_constructor_init = {
 static njs_ret_t
 njs_function_prototype_call(njs_vm_t *vm, njs_param_t *param)
 {
-    uintptr_t          nargs;
-    njs_ret_t          ret;
-    njs_param_t        p;
-    njs_value_t        *func;
-    njs_vmcode_call_t  *call;
+    uintptr_t                   nargs;
+    njs_ret_t                   ret;
+    njs_param_t                 p;
+    njs_value_t                 *func;
+    njs_function_t              *function;
+    njs_vmcode_function_call_t  *call;
 
     p.object = &param->args[0];
     p.args = &param->args[1];
@@ -400,13 +290,15 @@ njs_function_prototype_call(njs_vm_t *vm, njs_param_t *param)
         return NXT_ERROR;
     }
 
-    if (func->data.u.function->native) {
+    function = func->data.u.function;
+
+    if (function->native) {
 
         if (nargs != 0) {
             p.nargs = nargs - 1;
             p.retval = param->retval;
 
-            return func->data.u.function->code.native(vm, &p);
+            return function->u.native(vm, &p);
         }
 
         vm->exception = &njs_exception_type_error;
@@ -422,30 +314,31 @@ njs_function_prototype_call(njs_vm_t *vm, njs_param_t *param)
 
     p.nargs = nargs;
 
-    ret = njs_vmcode_function_frame(vm, func, &p, 0);
+    ret = njs_function_frame(vm, function, &p, 0);
 
     if (nxt_slow_path(ret != NXT_OK)) {
         return NXT_ERROR;
     }
 
     /* Skip the "call" method frame. */
-    vm->frame->previous = vm->frame->previous->previous;
+    vm->frame->previous->skip = 1;
 
-    call = (njs_vmcode_call_t *) vm->current;
+    call = (njs_vmcode_function_call_t *) vm->current;
 
-    return njs_function_call(vm, func->data.u.function, call->retval);
+    return njs_function_call(vm, call->retval);
 }
 
 
 static njs_ret_t
 njs_function_prototype_apply(njs_vm_t *vm, njs_param_t *param)
 {
-    uintptr_t          nargs;
-    njs_ret_t          ret;
-    njs_param_t        p;
-    njs_array_t        *array;
-    njs_value_t        *func, *args;
-    njs_vmcode_call_t  *code;
+    uintptr_t                   nargs;
+    njs_ret_t                   ret;
+    njs_param_t                 p;
+    njs_array_t                 *array;
+    njs_value_t                 *func, *args;
+    njs_function_t              *function;
+    njs_vmcode_function_call_t  *code;
 
     args = param->args;
     p.object = &args[0];
@@ -481,7 +374,9 @@ njs_function_prototype_apply(njs_vm_t *vm, njs_param_t *param)
         return func->data.u.method(vm, &p);
     }
 
-    if (func->data.u.function->native) {
+    function = func->data.u.function;
+
+    if (function->native) {
         p.retval = param->retval;
 
         if (nargs < 2) {
@@ -494,7 +389,7 @@ njs_function_prototype_apply(njs_vm_t *vm, njs_param_t *param)
             }
         }
 
-        return func->data.u.function->code.native(vm, &p);
+        return function->u.native(vm, &p);
     }
 
     if (nargs < 2) {
@@ -506,15 +401,15 @@ njs_function_prototype_apply(njs_vm_t *vm, njs_param_t *param)
         }
     }
 
-    ret = njs_vmcode_function_frame(vm, func, &p, 0);
+    ret = njs_function_frame(vm, function, &p, 0);
 
     if (nxt_fast_path(ret == NXT_OK)) {
         /* Skip the "apply" method frame. */
-        vm->frame->previous = vm->frame->previous->previous;
+        vm->frame->previous->skip = 1;
 
-        code = (njs_vmcode_call_t *) vm->current;
+        code = (njs_vmcode_function_call_t *) vm->current;
 
-        return njs_function_call(vm, func->data.u.function, code->retval);
+        return njs_function_call(vm, code->retval);
     }
 
     return NXT_ERROR;
@@ -533,8 +428,7 @@ njs_function_prototype_bind(njs_vm_t *vm, njs_param_t *param)
     njs_value_t     *func;
     njs_function_t  *bound;
 
-    bound = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t),
-                                sizeof(njs_function_t));
+    bound = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_function_t));
 
     if (nxt_fast_path(bound != NULL)) {
         nxt_lvlhsh_init(&bound->object.hash);
@@ -543,7 +437,7 @@ njs_function_prototype_bind(njs_vm_t *vm, njs_param_t *param)
         bound->args_offset = 1;
 
         func = param->object;
-        bound->code.script = func->data.u.function->code.script;
+        bound->u.lambda = func->data.u.function->u.lambda;
 
         vm->retval.data.u.function = bound;
         vm->retval.type = NJS_FUNCTION;
index 51db59b5c2104486e38496ab80d4b58e2d4367be..f30848bde22405f47ee3d4e3e77f5f89786e1944 100644 (file)
@@ -8,20 +8,15 @@
 #define _NJS_FUNCTION_H_INCLUDED_
 
 
-struct njs_function_script_s {
+struct njs_function_lambda_s {
     uint32_t                       nargs;
     uint32_t                       local_size;
-    /*
-     * Native methods do not allocate frame space so calling function
-     * reserves space in its scope for method frame and arguments.
-     */
-    uint32_t                       spare_size;
 
     /* Initial values of local scope. */
     njs_value_t                    *local_scope;
 
     union {
-        u_char                     *code;
+        u_char                     *start;
         njs_parser_t               *parser;
     } u;
 };
@@ -61,21 +56,53 @@ struct njs_exception_s {
 
 
 struct njs_native_frame_s {
-    u_char                         *last;
-    njs_native_frame_t             *previous;
-    njs_value_t                    *arguments;
+    u_char                         *free;
 
+    /*
+     * The return_address is required in njs_frame_t only, however, it
+     * can be stored here just after function adddress has been fetched.
+     */
     union {
+        njs_function_t             *function;
+        u_char                     *return_address;
+        njs_native_t               native;
         u_char                     *restart;
-        njs_exception_t            exception;
     } u;
 
-    uint32_t                       size;
+    njs_native_frame_t             *previous;
+    njs_value_t                    *arguments;
+
+    njs_exception_t                exception;
+
+    uint32_t                       free_size;
+
+    /* Script or native function or method. */
+    uint8_t                        native;          /* 1 bit  */
 
-    uint8_t                        start;           /* 1 bit */
-    uint8_t                        ctor;            /* 1 bit */
-    uint8_t                        reentrant;       /* 1 bit */
-    uint8_t                        trap_reference;  /* 1 bit */
+    /* Function is called as constructor with "new" keyword. */
+    uint8_t                        ctor;            /* 1 bit  */
+
+    /*
+     * The first frame in chunk.
+     * 7 bits are just to possibly initialize first and skip
+     * fields with one operation.
+     */
+    uint8_t                        first:7;          /* 1 bit  */
+
+    /* Skip the Function.call() and Function.apply() methods frames. */
+    uint8_t                        skip:1;           /* 1 bit  */
+
+    /*
+     * The function is reentrant.  It is usually used as a flag,
+     * however, in traps it used to allow just two entrances.
+     */
+    uint8_t                        reentrant:7;    /* 2 bits  */
+
+    /*
+     * The first operand in trap is reference to original value,
+     * it is used to increment or decrement this value.
+     */
+    uint8_t                        trap_reference:1;
 };
 
 
@@ -88,22 +115,19 @@ typedef struct {
     njs_value_t                    *closure;
 
     njs_index_t                    retval;
-    u_char                         *return_address;
 } njs_frame_t;
 
 
 njs_function_t *njs_function_alloc(njs_vm_t *vm);
+njs_native_frame_t *njs_function_frame_alloc(njs_vm_t *vm, size_t size);
 njs_ret_t njs_function_constructor(njs_vm_t *vm, njs_param_t *param);
 njs_ret_t njs_function_apply(njs_vm_t *vm, njs_value_t *name,
     njs_param_t *param);
-njs_value_t *njs_vmcode_native_frame(njs_vm_t *vm, njs_value_t *method,
-    uintptr_t nargs, nxt_bool_t ctor);
-njs_ret_t njs_vmcode_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1,
-    njs_value_t *value2);
-njs_ret_t njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *name,
+njs_value_t *njs_function_native_frame(njs_vm_t *vm, njs_native_t native,
+    size_t local_size, njs_vmcode_t *code);
+njs_ret_t njs_function_frame(njs_vm_t *vm, njs_function_t *function,
     njs_param_t *param, nxt_bool_t ctor);
-njs_ret_t njs_function_call(njs_vm_t *vm, njs_function_t *func,
-    njs_index_t retval);
+njs_ret_t njs_function_call(njs_vm_t *vm, njs_index_t retval);
 
 extern const njs_object_init_t  njs_function_constructor_init;
 extern const njs_object_init_t  njs_function_prototype_init;
index 27a1c56ebe024104798e65472dcde05af3e7d6e2..f66fb4435db3d007c2c0043fcc82c918f1a3039a 100644 (file)
@@ -57,7 +57,7 @@ static nxt_int_t njs_generate_2addr_operation(njs_vm_t *vm,
     njs_parser_t *parser, njs_parser_node_t *node);
 static nxt_int_t njs_generate_inc_dec_operation(njs_vm_t *vm,
     njs_parser_t *parser, njs_parser_node_t *node, nxt_bool_t post);
-static nxt_int_t njs_generate_function_statement(njs_vm_t *vm,
+static nxt_int_t njs_generate_function_declaration(njs_vm_t *vm,
     njs_parser_t *parser, njs_parser_node_t *node);
 static nxt_int_t njs_generate_return_statement(njs_vm_t *vm,
     njs_parser_t *parser, njs_parser_node_t *node);
@@ -225,20 +225,20 @@ njs_generator(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
 
         return NXT_ERROR;
 
-    case NJS_TOKEN_OBJECT_LITERAL:
+    case NJS_TOKEN_OBJECT_VALUE:
         node->index = node->u.object->index;
         return NXT_OK;
 
-    case NJS_TOKEN_OBJECT_CREATE:
+    case NJS_TOKEN_OBJECT:
         return njs_generate_object(vm, parser, node);
 
-    case NJS_TOKEN_ARRAY_CREATE:
+    case NJS_TOKEN_ARRAY:
         return njs_generate_array(vm, parser, node);
 
-    case NJS_TOKEN_FUNCTION_CREATE:
+    case NJS_TOKEN_FUNCTION_EXPRESSION:
         return njs_generate_function(vm, parser, node);
 
-    case NJS_TOKEN_REGEXP_LITERAL:
+    case NJS_TOKEN_REGEXP:
         return njs_generate_regexp(vm, parser, node);
 
     case NJS_TOKEN_THIS:
@@ -257,7 +257,7 @@ njs_generator(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
         return njs_generate_variable(parser, node);
 
     case NJS_TOKEN_FUNCTION:
-        return njs_generate_function_statement(vm, parser, node);
+        return njs_generate_function_declaration(vm, parser, node);
 
     case NJS_TOKEN_FUNCTION_CALL:
         return njs_generate_function_call(vm, parser, node);
@@ -944,7 +944,7 @@ njs_generate_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
     }
 
     njs_generate_code(parser, njs_vmcode_object_t, obj);
-    obj->code.operation = njs_vmcode_object_create;
+    obj->code.operation = njs_vmcode_object;
     obj->code.operands = NJS_VMCODE_1OPERAND;
     obj->code.retval = NJS_VMCODE_RETVAL;
     obj->retval = index;
@@ -996,7 +996,7 @@ njs_generate_array(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
     }
 
     njs_generate_code(parser, njs_vmcode_array_t, array);
-    array->code.operation = njs_vmcode_array_create;
+    array->code.operation = njs_vmcode_array;
     array->code.operands = NJS_VMCODE_1OPERAND;
     array->code.retval = NJS_VMCODE_RETVAL;
     array->retval = index;
@@ -1030,34 +1030,19 @@ static nxt_int_t
 njs_generate_function(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node)
 {
-    nxt_int_t                     ret;
-    njs_index_t                   index;
-    njs_parser_node_t             *body;
-    njs_function_script_t         *func;
-    njs_vmcode_operation_t        last;
-    njs_vmcode_function_create_t  *function;
-
-    body = node->right;
-
-    if (body != NULL
-        && body->right != NULL
-        && body->right->token == NJS_TOKEN_RETURN)
-    {
-        last = NULL;
-
-    } else {
-        last = njs_vmcode_return;
-    }
+    nxt_int_t              ret;
+    njs_index_t            index;
+    njs_function_lambda_t  *lambda;
+    njs_vmcode_function_t  *function;
 
-    func = node->u.value.data.u.data;
+    lambda = node->u.value.data.u.lambda;
 
-    ret = njs_generate_scope(vm, func->u.parser, body, last);
+    ret = njs_generate_scope(vm, lambda->u.parser, node->right);
 
     if (nxt_fast_path(ret == NXT_OK)) {
-        func->local_size = func->u.parser->scope_size;
-        func->spare_size = func->u.parser->method_arguments_size;
-        func->local_scope = func->u.parser->local_scope;
-        func->u.code = func->u.parser->code_start;
+        lambda->local_size = lambda->u.parser->scope_size;
+        lambda->local_scope = lambda->u.parser->local_scope;
+        lambda->u.start = lambda->u.parser->code_start;
 
         /* Try to assign directly to variable. */
 
@@ -1067,15 +1052,16 @@ njs_generate_function(njs_vm_t *vm, njs_parser_t *parser,
         }
 
         if (index == NJS_INDEX_NONE) {
+            node->temporary = 1;
             index = njs_generator_temp_index_get(parser);
         }
 
-        njs_generate_code(parser, njs_vmcode_function_create_t, function);
-        function->code.operation = njs_vmcode_function_create;
+        njs_generate_code(parser, njs_vmcode_function_t, function);
+        function->code.operation = njs_vmcode_function;
         function->code.operands = NJS_VMCODE_1OPERAND;
         function->code.retval = NJS_VMCODE_RETVAL;
         function->retval = index;
-        function->function = func;
+        function->lambda = lambda;
 
         node->index = index;
 
@@ -1104,7 +1090,7 @@ njs_generate_regexp(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
     }
 
     njs_generate_code(parser, njs_vmcode_regexp_t, regexp);
-    regexp->code.operation = njs_vmcode_regexp_create;
+    regexp->code.operation = njs_vmcode_regexp;
     regexp->code.operands = NJS_VMCODE_1OPERAND;
     regexp->code.retval = NJS_VMCODE_RETVAL;
     regexp->retval = index;
@@ -1433,39 +1419,24 @@ njs_generate_inc_dec_operation(njs_vm_t *vm, njs_parser_t *parser,
 
 
 static nxt_int_t
-njs_generate_function_statement(njs_vm_t *vm, njs_parser_t *parser,
+njs_generate_function_declaration(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node)
 {
-    nxt_int_t               ret;
-    njs_value_t             *value;
-    njs_function_t          *func;
-    njs_parser_node_t       *body;
-    njs_vmcode_operation_t  last;
+    nxt_int_t       ret;
+    njs_value_t     *value;
+    njs_function_t  *func;
 
     value = njs_variable_value(parser, node->index);
     func = value->data.u.function;
 
-    body = node->right;
-
-    if (body != NULL
-        && body->right != NULL
-        && body->right->token == NJS_TOKEN_RETURN)
-    {
-        last = NULL;
-
-    } else {
-        last = njs_vmcode_return;
-    }
-
-    ret = njs_generate_scope(vm, func->code.script->u.parser, body, last);
+    ret = njs_generate_scope(vm, func->u.lambda->u.parser, node->right);
 
     if (nxt_fast_path(ret == NXT_OK)) {
-        parser = func->code.script->u.parser;
+        parser = func->u.lambda->u.parser;
 
-        func->code.script->local_size = parser->scope_size;
-        func->code.script->spare_size = parser->method_arguments_size;
-        func->code.script->local_scope = parser->local_scope;
-        func->code.script->u.code = parser->code_start;
+        func->u.lambda->local_size = parser->scope_size;
+        func->u.lambda->local_scope = parser->local_scope;
+        func->u.lambda->u.start = parser->code_start;
         node->u.value = *value;
     }
 
@@ -1474,8 +1445,7 @@ njs_generate_function_statement(njs_vm_t *vm, njs_parser_t *parser,
 
 
 nxt_int_t
-njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node,
-    njs_vmcode_operation_t last)
+njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
 {
     size_t             code_size, size;
     u_char             *p;
@@ -1500,16 +1470,17 @@ njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node,
         }
     }
 
-    if (last != NULL) {
+    if (parser->scope == NJS_SCOPE_GLOBAL) {
         njs_generate_code(parser, njs_vmcode_stop_t, stop);
-        stop->code.operation = last;
+        stop->code.operation = njs_vmcode_stop;
         stop->code.operands = NJS_VMCODE_1OPERAND;
         stop->code.retval = NJS_VMCODE_NO_RETVAL;
 
-        index = njs_value_index(vm, parser, &njs_value_void);
-
-        if (last == njs_vmcode_stop && node->index != 0) {
+        if (node->index != 0) {
             index = node->index;
+
+        } else {
+            index = njs_value_index(vm, parser, &njs_value_void);
         }
 
         stop->retval = index;
@@ -1569,14 +1540,14 @@ static nxt_int_t
 njs_generate_return_statement(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node)
 {
-    nxt_int_t          ret;
-    njs_index_t        index;
-    njs_vmcode_stop_t  *code;
+    nxt_int_t            ret;
+    njs_index_t          index;
+    njs_vmcode_return_t  *code;
 
     ret = njs_generator(vm, parser, node->right);
 
     if (nxt_fast_path(ret == NXT_OK)) {
-        njs_generate_code(parser, njs_vmcode_stop_t, code);
+        njs_generate_code(parser, njs_vmcode_return_t, code);
         code->code.operation = njs_vmcode_return;
         code->code.operands = NJS_VMCODE_1OPERAND;
         code->code.retval = NJS_VMCODE_NO_RETVAL;
@@ -1600,13 +1571,13 @@ static nxt_int_t
 njs_generate_function_call(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node)
 {
-    uintptr_t              nargs;
-    nxt_int_t              ret;
-    njs_index_t            retval, index, name;
-    njs_parser_node_t      *arg;
-    njs_vmcode_call_t      *call;
-    njs_vmcode_move_t      *move;
-    njs_vmcode_function_t  *func;
+    uintptr_t                    nargs;
+    nxt_int_t                    ret;
+    njs_index_t                  retval;
+    njs_parser_node_t            *arg, *name;
+    njs_vmcode_move_t            *move;
+    njs_vmcode_function_call_t   *call;
+    njs_vmcode_function_frame_t  *func;
 
     if (node->left != NULL) {
         /* Generate function code in function expression. */
@@ -1615,23 +1586,25 @@ njs_generate_function_call(njs_vm_t *vm, njs_parser_t *parser,
             return ret;
         }
 
-        name = node->left->index;
+        name = node->left;
 
     } else {
         /* njs_generate_variable() always returns NXT_OK. */
         (void) njs_generate_variable(parser, node);
-        name = node->index;
+        name = node;
     }
 
-    njs_generate_code(parser, njs_vmcode_function_t, func);
-    func->code.operation = njs_vmcode_function;
-    func->code.operands = NJS_VMCODE_2OPERANDS;
-    func->code.retval = NJS_VMCODE_RETVAL;
+    njs_generate_code(parser, njs_vmcode_function_frame_t, func);
+    func->code.operation = njs_vmcode_function_frame;
+    func->code.operands = NJS_VMCODE_1OPERAND;
+    func->code.retval = NJS_VMCODE_NO_RETVAL;
     func->code.ctor = node->ctor;
-    func->name = name;
+    func->name = name->index;
 
-    index = njs_generator_temp_index_get(parser);
-    func->function = index;
+    ret = njs_generator_node_index_release(vm, parser, name);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return ret;
+    }
 
     nargs = 1;
 
@@ -1663,24 +1636,19 @@ njs_generate_function_call(njs_vm_t *vm, njs_parser_t *parser,
 
     if (retval == NJS_INDEX_NONE) {
         node->temporary = 1;
-        retval = index;
+        retval = njs_generator_temp_index_get(parser);
     }
 
     node->index = retval;
 
-    njs_generate_code(parser, njs_vmcode_call_t, call);
-    call->code.operation = njs_vmcode_call;
-    call->code.operands = NJS_VMCODE_2OPERANDS;
+    njs_generate_code(parser, njs_vmcode_function_call_t, call);
+    call->code.operation = njs_vmcode_function_call;
+    call->code.operands = NJS_VMCODE_1OPERAND;
     call->code.retval = NJS_VMCODE_NO_RETVAL;
     call->code.nargs = nargs;
-    call->function = index;
     call->retval = retval;
 
-    if (retval == index) {
-        return NXT_OK;
-    }
-
-    return njs_generator_index_release(vm, parser, index);
+    return NXT_OK;
 }
 
 
@@ -1688,13 +1656,13 @@ static nxt_int_t
 njs_generate_method_call(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node)
 {
-    uintptr_t            nargs;
-    nxt_int_t            ret;
-    njs_index_t          retval, index;
-    njs_parser_node_t    *arg, *prop;
-    njs_vmcode_call_t    *call;
-    njs_vmcode_move_t    *move;
-    njs_vmcode_method_t  *method;
+    uintptr_t                   nargs;
+    nxt_int_t                   ret;
+    njs_index_t                 retval;
+    njs_parser_node_t           *arg, *prop;
+    njs_vmcode_move_t           *move;
+    njs_vmcode_method_frame_t   *method;
+    njs_vmcode_function_call_t  *call;
 
     prop = node->left;
 
@@ -1712,30 +1680,19 @@ njs_generate_method_call(njs_vm_t *vm, njs_parser_t *parser,
         return ret;
     }
 
-    if (prop->left->temporary) {
-        index = prop->left->index;
-
-        ret = njs_generator_node_index_release(vm, parser, prop->right);
-        if (nxt_slow_path(ret != NXT_OK)) {
-            return ret;
-        }
-
-    } else if (prop->right->temporary) {
-        index = prop->right->index;
-
-    } else {
-        index = njs_generator_temp_index_get(parser);
-    }
-
-    njs_generate_code(parser, njs_vmcode_method_t, method);
-    method->code.operation = njs_vmcode_method;
-    method->code.operands = NJS_VMCODE_3OPERANDS;
-    method->code.retval = NJS_VMCODE_RETVAL;
+    njs_generate_code(parser, njs_vmcode_method_frame_t, method);
+    method->code.operation = njs_vmcode_method_frame;
+    method->code.operands = NJS_VMCODE_2OPERANDS;
+    method->code.retval = NJS_VMCODE_NO_RETVAL;
     method->code.ctor = node->ctor;
-    method->function = index;
     method->object = prop->left->index;
     method->method = prop->right->index;
 
+    ret = njs_generator_children_indexes_release(vm, parser, prop);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return ret;
+    }
+
     nargs = 1;
 
     for (arg = node->right; arg != NULL; arg = arg->right) {
@@ -1766,24 +1723,19 @@ njs_generate_method_call(njs_vm_t *vm, njs_parser_t *parser,
 
     if (retval == NJS_INDEX_NONE) {
         node->temporary = 1;
-        retval = index;
+        retval = njs_generator_temp_index_get(parser);
     }
 
     node->index = retval;
 
-    njs_generate_code(parser, njs_vmcode_call_t, call);
-    call->code.operation = njs_vmcode_call;
-    call->code.operands = NJS_VMCODE_2OPERANDS;
+    njs_generate_code(parser, njs_vmcode_function_call_t, call);
+    call->code.operation = njs_vmcode_function_call;
+    call->code.operands = NJS_VMCODE_1OPERAND;
     call->code.retval = NJS_VMCODE_NO_RETVAL;
     call->code.nargs = nargs;
-    call->function = index;
     call->retval = retval;
 
-    if (retval == index) {
-        return NXT_OK;
-    }
-
-    return njs_generator_index_release(vm, parser, index);
+    return NXT_OK;
 }
 
 
index 3db099f22dedad8d39aaca9110a5a5c42fa572e4..a33b45eabfb1e771183b5731c11291aa151a73b4 100644 (file)
 static njs_token_t njs_parser_statement(njs_vm_t *vm, njs_parser_t *parser,
     njs_token_t token);
 static njs_token_t njs_parser_block(njs_vm_t *vm, njs_parser_t *parser);
-static njs_token_t njs_parser_function_statement(njs_vm_t *vm,
+static njs_token_t njs_parser_function_declaration(njs_vm_t *vm,
     njs_parser_t *parser);
+static njs_parser_t *njs_parser_function_create(njs_vm_t *vm,
+    njs_parser_t *parent);
+static njs_token_t njs_parser_function_lambda(njs_vm_t *vm,
+    njs_function_lambda_t *lambda, njs_token_t token);
 static njs_token_t njs_parser_return_statement(njs_vm_t *vm,
     njs_parser_t *parser);
 static njs_token_t njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser);
@@ -135,7 +139,7 @@ njs_parser_statement(njs_vm_t *vm, njs_parser_t *parser,
     switch (token) {
 
     case NJS_TOKEN_FUNCTION:
-        return njs_parser_function_statement(vm, parser);
+        return njs_parser_function_declaration(vm, parser);
 
     case NJS_TOKEN_RETURN:
         return njs_parser_return_statement(vm, parser);
@@ -256,15 +260,13 @@ njs_parser_match(njs_parser_t *parser, njs_token_t token,
 
 
 static njs_token_t
-njs_parser_function_statement(njs_vm_t *vm, njs_parser_t *parser)
+njs_parser_function_declaration(njs_vm_t *vm, njs_parser_t *parser)
 {
-    nxt_str_t          *name;
     nxt_uint_t         level;
-    njs_index_t        index;
-    njs_value_t        *value;
     njs_token_t        token;
-    njs_parser_t       *fn_parser;
-    njs_variable_t     *arg, *var;
+    njs_value_t        *value;
+    njs_variable_t     *var;
+    njs_function_t     *function;
     njs_parser_node_t  *node;
 
     node = njs_parser_node_alloc(vm);
@@ -279,168 +281,70 @@ njs_parser_function_statement(njs_vm_t *vm, njs_parser_t *parser)
         return token;
     }
 
-    if (token == NJS_TOKEN_NAME) {
-        nxt_thread_log_debug("function: %V", &parser->lexer->text);
-
-        var = njs_parser_variable(vm, parser, &level);
-        if (nxt_slow_path(var == NULL)) {
-            return NJS_TOKEN_ERROR;
-        }
-
-        var->state = NJS_VARIABLE_DECLARED;
-
-        token = njs_parser_token(parser);
-        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-            return token;
-        }
-
-        index = var->index;
-        value = njs_variable_value(parser, index);
-
-    } else {
-        /* Anonymous function. */
-        value = nxt_array_add(parser->scope_values, &njs_array_mem_proto,
-                              vm->mem_cache_pool);
-        if (nxt_slow_path(value == NULL)) {
-            return NJS_TOKEN_ERROR;
-        }
-
-        index = njs_parser_index(parser, parser->scope);
-    }
-
-    value->type = NJS_FUNCTION;
-    node->index = index;
-
-    token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
-    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-        return token;
-    }
-
-    value->data.u.function = njs_function_alloc(vm);
-    if (nxt_slow_path(value->data.u.function == NULL)) {
-        return NJS_TOKEN_ERROR;
-    }
-
-    fn_parser = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_parser_t));
-    if (nxt_slow_path(fn_parser == NULL)) {
+    if (token != NJS_TOKEN_NAME) {
         return NJS_TOKEN_ERROR;
     }
 
-    value->data.u.function->code.script->u.parser = fn_parser;
-
-    fn_parser->lexer = parser->lexer;
-
-    /* njs_vmcode_return() size. */
-    fn_parser->code_size = sizeof(njs_vmcode_stop_t);
-
-    fn_parser->arguments = nxt_array_create(4, sizeof(njs_variable_t),
-                                            &njs_array_mem_proto,
-                                            vm->mem_cache_pool);
-    if (nxt_slow_path(fn_parser->arguments == NULL)) {
+    var = njs_parser_variable(vm, parser, &level);
+    if (nxt_slow_path(var == NULL)) {
         return NJS_TOKEN_ERROR;
     }
 
-    fn_parser->parent = parser;
-
-    vm->parser = fn_parser;
-
-    index = NJS_SCOPE_ARGUMENTS;
-
-    /* A "this" reservation. */
-    index += sizeof(njs_value_t);
-
-    while (token != NJS_TOKEN_CLOSE_PARENTHESIS) {
-
-        if (nxt_slow_path(token != NJS_TOKEN_NAME)) {
-            return NJS_TOKEN_ERROR;
-        }
-
-        name = &fn_parser->lexer->text;
-
-        nxt_thread_log_debug("arg: %V", name);
-
-        arg = nxt_array_add(fn_parser->arguments, &njs_array_mem_proto,
-                            vm->mem_cache_pool);
-        if (nxt_slow_path(arg == NULL)) {
-            return NJS_TOKEN_ERROR;
-        }
-
-        arg->name_start = nxt_mem_cache_alloc(vm->mem_cache_pool, name->len);
-        if (nxt_slow_path(arg->name_start == NULL)) {
-            return NJS_TOKEN_ERROR;
-        }
-
-        memcpy(arg->name_start, name->data, name->len);
-        arg->name_len = name->len;
-
-        arg->state = NJS_VARIABLE_DECLARED;
-        arg->index = index;
-        index += sizeof(njs_value_t);
-
-        token = njs_parser_token(fn_parser);
-        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-            return token;
-        }
-
-        if (token == NJS_TOKEN_COMMA) {
-            token = njs_parser_token(fn_parser);
-            if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-                return token;
-            }
-        }
-    }
+    var->state = NJS_VARIABLE_DECLARED;
+    node->index = var->index;
 
-    value->data.u.function->code.script->nargs =
-                                   njs_index_size(index) / sizeof(njs_value_t);
-
-    token = njs_parser_token(fn_parser);
+    token = njs_parser_token(parser);
     if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
         return token;
     }
 
-    if (nxt_slow_path(token != NJS_TOKEN_OPEN_BRACE)) {
-        return NJS_TOKEN_ERROR;
-    }
+    parser->node = node;
 
-    fn_parser->scope_values = nxt_array_create(4, sizeof(njs_value_t),
-                                               &njs_array_mem_proto,
-                                               vm->mem_cache_pool);
-    if (nxt_slow_path(fn_parser->scope_values == NULL)) {
-        return NXT_ERROR;
+    function = njs_function_alloc(vm);
+    if (nxt_slow_path(function == NULL)) {
+        return NJS_TOKEN_ERROR;
     }
 
-    fn_parser->scope = NJS_SCOPE_LOCAL;
-
-    token = njs_parser_block(vm, fn_parser);
+    value = njs_variable_value(parser, node->index);
+    value->data.u.function = function;
+    value->type = NJS_FUNCTION;
 
-    vm->parser = parser;
-    node->right = fn_parser->node;
+    parser = njs_parser_function_create(vm, parser);
+    if (nxt_slow_path(parser == NULL)) {
+        return NJS_TOKEN_ERROR;
+    }
 
-    parser->node = node;
+    function->u.lambda->u.parser = parser;
 
-    return token;
+    return njs_parser_function_lambda(vm, function->u.lambda, token);
 }
 
 
 static njs_token_t
 njs_parser_function_expression(njs_vm_t *vm, njs_parser_t *parser)
 {
-    nxt_str_t              *name;
     nxt_uint_t             level;
+    njs_token_t            token;
     njs_index_t            index;
     njs_value_t            *value;
-    njs_token_t            token;
-    njs_parser_t           *fn_parser;
-    njs_variable_t         *arg, *var;
+    njs_variable_t         *var;
+    njs_function_t         *function;
     njs_parser_node_t      *node;
-    njs_function_script_t  *func;
+    njs_function_lambda_t  *lambda;
 
     node = njs_parser_node_alloc(vm);
     if (nxt_slow_path(node == NULL)) {
         return NJS_TOKEN_ERROR;
     }
 
-    node->token = NJS_TOKEN_FUNCTION_CREATE;
+    node->token = NJS_TOKEN_FUNCTION_EXPRESSION;
+    parser->node = node;
+    parser->code_size += sizeof(njs_vmcode_function_t);
+
+    parser = njs_parser_function_create(vm, parser);
+    if (nxt_slow_path(parser == NULL)) {
+        return NJS_TOKEN_ERROR;
+    }
 
     token = njs_parser_token(parser);
     if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
@@ -448,56 +352,98 @@ njs_parser_function_expression(njs_vm_t *vm, njs_parser_t *parser)
     }
 
     if (token == NJS_TOKEN_NAME) {
-        nxt_thread_log_debug("function: %V", &parser->lexer->text);
-
         var = njs_parser_variable(vm, parser, &level);
         if (nxt_slow_path(var == NULL)) {
             return NJS_TOKEN_ERROR;
         }
 
+        var->state = NJS_VARIABLE_DECLARED;
+
         token = njs_parser_token(parser);
         if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
             return token;
         }
+
+        index = var->index;
+        value = njs_variable_value(parser, index);
+
+        function = njs_function_alloc(vm);
+        if (nxt_slow_path(function == NULL)) {
+            return NJS_TOKEN_ERROR;
+        }
+
+        value->data.u.function = function;
+        value->type = NJS_FUNCTION;
+        lambda = function->u.lambda;
+
+    } else {
+        /* Anonymous function. */
+        lambda = nxt_mem_cache_zalloc(vm->mem_cache_pool,
+                                      sizeof(njs_function_lambda_t));
+        if (nxt_slow_path(lambda == NULL)) {
+            return NJS_TOKEN_ERROR;
+        }
     }
 
-    value = &node->u.value;
+    node->u.value.data.u.lambda = lambda;
+    lambda->u.parser = parser;
 
-    token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
-    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-        return token;
+    return njs_parser_function_lambda(vm, lambda, token);
+}
+
+
+static njs_parser_t *
+njs_parser_function_create(njs_vm_t *vm, njs_parser_t *parent)
+{
+    nxt_array_t   *values, *arguments;
+    njs_parser_t  *parser;
+
+    parser = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_parser_t));
+    if (nxt_slow_path(parser == NULL)) {
+        return NULL;
     }
 
-    func = nxt_mem_cache_zalloc(vm->mem_cache_pool,
-                                sizeof(njs_function_script_t));
-    if (nxt_slow_path(func == NULL)) {
-        return NJS_TOKEN_ERROR;
+    parser->parent = parent;
+    parser->lexer = parent->lexer;
+    vm->parser = parser;
+
+    arguments = nxt_array_create(4, sizeof(njs_variable_t),
+                                 &njs_array_mem_proto, vm->mem_cache_pool);
+    if (nxt_slow_path(arguments == NULL)) {
+        return NULL;
     }
 
-    value->data.u.data = func;
+    parser->arguments = arguments;
 
-    fn_parser = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_parser_t));
-    if (nxt_slow_path(fn_parser == NULL)) {
-        return NJS_TOKEN_ERROR;
+    values = nxt_array_create(4, sizeof(njs_value_t), &njs_array_mem_proto,
+                              vm->mem_cache_pool);
+    if (nxt_slow_path(values == NULL)) {
+        return NULL;
     }
 
-    func->u.parser = fn_parser;
+    parser->scope_values = values;
+    parser->scope = NJS_SCOPE_LOCAL;
 
-    fn_parser->lexer = parser->lexer;
+    return parser;
+}
 
-    /* njs_vmcode_return() size. */
-    fn_parser->code_size = sizeof(njs_vmcode_stop_t);
 
-    fn_parser->arguments = nxt_array_create(4, sizeof(njs_variable_t),
-                                            &njs_array_mem_proto,
-                                            vm->mem_cache_pool);
-    if (nxt_slow_path(fn_parser->arguments == NULL)) {
-        return NJS_TOKEN_ERROR;
-    }
+static njs_token_t
+njs_parser_function_lambda(njs_vm_t *vm, njs_function_lambda_t *lambda,
+    njs_token_t token)
+{
+    nxt_str_t          *name;
+    njs_index_t        index;
+    njs_parser_t       *parser;
+    njs_variable_t     *arg;
+    njs_parser_node_t  *node, *body;
 
-    fn_parser->parent = parser;
+    parser = lambda->u.parser;
 
-    vm->parser = fn_parser;
+    token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
+    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+        return token;
+    }
 
     index = NJS_SCOPE_ARGUMENTS;
 
@@ -510,16 +456,14 @@ njs_parser_function_expression(njs_vm_t *vm, njs_parser_t *parser)
             return NJS_TOKEN_ERROR;
         }
 
-        name = &fn_parser->lexer->text;
-
-        nxt_thread_log_debug("arg: %V", name);
-
-        arg = nxt_array_add(fn_parser->arguments, &njs_array_mem_proto,
+        arg = nxt_array_add(parser->arguments, &njs_array_mem_proto,
                             vm->mem_cache_pool);
         if (nxt_slow_path(arg == NULL)) {
             return NJS_TOKEN_ERROR;
         }
 
+        name = &parser->lexer->text;
+
         arg->name_start = nxt_mem_cache_alloc(vm->mem_cache_pool, name->len);
         if (nxt_slow_path(arg->name_start == NULL)) {
             return NJS_TOKEN_ERROR;
@@ -532,22 +476,22 @@ njs_parser_function_expression(njs_vm_t *vm, njs_parser_t *parser)
         arg->index = index;
         index += sizeof(njs_value_t);
 
-        token = njs_parser_token(fn_parser);
+        token = njs_parser_token(parser);
         if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
             return token;
         }
 
         if (token == NJS_TOKEN_COMMA) {
-            token = njs_parser_token(fn_parser);
+            token = njs_parser_token(parser);
             if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
                 return token;
             }
         }
     }
 
-    func->nargs = njs_index_size(index) / sizeof(njs_value_t);
+    lambda->nargs = njs_index_size(index) / sizeof(njs_value_t);
 
-    token = njs_parser_token(fn_parser);
+    token = njs_parser_token(parser);
     if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
         return token;
     }
@@ -556,22 +500,40 @@ njs_parser_function_expression(njs_vm_t *vm, njs_parser_t *parser)
         return NJS_TOKEN_ERROR;
     }
 
-    fn_parser->scope_values = nxt_array_create(4, sizeof(njs_value_t),
-                                               &njs_array_mem_proto,
-                                               vm->mem_cache_pool);
-    if (nxt_slow_path(fn_parser->scope_values == NULL)) {
-        return NXT_ERROR;
+    token = njs_parser_block(vm, parser);
+    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+        return token;
     }
 
-    fn_parser->scope = NJS_SCOPE_LOCAL;
+    /*
+     * There is no function body or the last function body statement is not
+     * "return" statement.  If function has body then the body->right node is
+     * always present and it is a NJS_TOKEN_STATEMENT link node.
+     */
+    body = parser->node;
 
-    token = njs_parser_block(vm, fn_parser);
+    if (body == NULL || body->right->token != NJS_TOKEN_RETURN) {
+        node = njs_parser_node_alloc(vm);
+        if (nxt_slow_path(node == NULL)) {
+            return NJS_TOKEN_ERROR;
+        }
 
-    vm->parser = parser;
-    node->right = fn_parser->node;
+        node->token = NJS_TOKEN_STATEMENT;
+        node->left = parser->node;
+        parser->node = node;
 
-    parser->node = node;
-    parser->code_size += sizeof(njs_vmcode_function_create_t);
+        node->right = njs_parser_node_alloc(vm);
+        if (nxt_slow_path(node->right == NULL)) {
+            return NJS_TOKEN_ERROR;
+        }
+
+        node->right->token = NJS_TOKEN_RETURN;
+
+        parser->code_size += sizeof(njs_vmcode_return_t);
+    }
+
+    parser->parent->node->right = parser->node;
+    vm->parser = parser->parent;
 
     return token;
 }
@@ -590,7 +552,7 @@ njs_parser_return_statement(njs_vm_t *vm, njs_parser_t *parser)
 
     node->token = NJS_TOKEN_RETURN;
     parser->node = node;
-    parser->code_size += sizeof(njs_vmcode_stop_t);
+    parser->code_size += sizeof(njs_vmcode_return_t);
 
     token = njs_lexer_token(parser->lexer);
     if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
@@ -1303,7 +1265,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token)
         break;
 
     case NJS_TOKEN_OPEN_BRACE:
-        node->token = NJS_TOKEN_OBJECT_CREATE;
+        node->token = NJS_TOKEN_OBJECT;
 
         nxt_thread_log_debug("JS: OBJECT");
 
@@ -1322,7 +1284,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token)
         return token;
 
     case NJS_TOKEN_OPEN_BRACKET:
-        node->token = NJS_TOKEN_ARRAY_CREATE;
+        node->token = NJS_TOKEN_ARRAY;
 
         nxt_thread_log_debug("JS: ARRAY");
 
@@ -1348,7 +1310,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token)
 
         nxt_thread_log_debug("REGEX: '%V'", &parser->lexer->text);
 
-        node->token = NJS_TOKEN_REGEXP_LITERAL;
+        node->token = NJS_TOKEN_REGEXP;
         parser->code_size += sizeof(njs_vmcode_regexp_t);
 
         break;
@@ -1488,7 +1450,7 @@ njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj)
             return NJS_TOKEN_ERROR;
         }
 
-        object->token = NJS_TOKEN_OBJECT_LITERAL;
+        object->token = NJS_TOKEN_OBJECT_VALUE;
         object->u.object = obj;
 
         propref = njs_parser_node_alloc(vm);
@@ -1591,7 +1553,7 @@ njs_parser_array(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj)
             return NJS_TOKEN_ERROR;
         }
 
-        object->token = NJS_TOKEN_OBJECT_LITERAL;
+        object->token = NJS_TOKEN_OBJECT_VALUE;
         object->u.object = obj;
 
         propref = njs_parser_node_alloc(vm);
index 69ca45562292893eda1fff2d9955e5b40b32d4e4..9f83268ff181a98a3dbb917697e511bd11066b08 100644 (file)
@@ -118,21 +118,21 @@ typedef enum {
     NJS_TOKEN_ESCAPE_STRING,
     NJS_TOKEN_NAME,
 
-    NJS_TOKEN_OBJECT_CREATE,
-    NJS_TOKEN_OBJECT_LITERAL,
+    NJS_TOKEN_OBJECT,
+    NJS_TOKEN_OBJECT_VALUE,
     NJS_TOKEN_PROPERTY,
     NJS_TOKEN_PROPERTY_DELETE,
 
-    NJS_TOKEN_ARRAY_CREATE,
+    NJS_TOKEN_ARRAY,
 
-    NJS_TOKEN_FUNCTION_CREATE,
     NJS_TOKEN_FUNCTION,
+    NJS_TOKEN_FUNCTION_EXPRESSION,
     NJS_TOKEN_FUNCTION_CALL,
     NJS_TOKEN_METHOD_CALL,
     NJS_TOKEN_ARGUMENT,
     NJS_TOKEN_RETURN,
 
-    NJS_TOKEN_REGEXP_LITERAL,
+    NJS_TOKEN_REGEXP,
 
     NJS_TOKEN_EXTERNAL,
 
@@ -261,10 +261,6 @@ struct njs_parser_s {
     size_t                          scope_size;
     size_t                          scope_offset;
 
-    uint32_t                        nesting_arguments;
-    uint32_t                        nesting_arguments_size;
-    uint32_t                        method_arguments_size;
-
     u_char                          *code_start;
     u_char                          *code_end;
 
@@ -298,7 +294,7 @@ nxt_int_t njs_parser_string_create(njs_vm_t *vm, njs_value_t *value);
 njs_index_t njs_parser_index(njs_parser_t *parser, uint32_t scope);
 nxt_bool_t njs_parser_has_side_effect(njs_parser_node_t *node);
 nxt_int_t njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser,
-    njs_parser_node_t *node, njs_vmcode_operation_t last);
+    njs_parser_node_t *node);
 
 
 #define njs_generate_code(parser, type, code)                                 \
index e50f55f61eb292be4818b51fbaf27c799380fd10..da22951983bc1eabb249818749fac77ec16c7c0f 100644 (file)
@@ -899,11 +899,11 @@ njs_parser_call_expression(njs_vm_t *vm, njs_parser_t *parser,
         case NJS_TOKEN_NAME:
             func = node;
             func->token = NJS_TOKEN_FUNCTION_CALL;
-            parser->code_size += sizeof(njs_vmcode_function_t)
-                                 + sizeof(njs_vmcode_call_t);
+            parser->code_size += sizeof(njs_vmcode_function_frame_t)
+                                 + sizeof(njs_vmcode_function_call_t);
             break;
 
-        case NJS_TOKEN_FUNCTION_CREATE:
+        case NJS_TOKEN_FUNCTION_EXPRESSION:
             func = njs_parser_node_alloc(vm);
             if (nxt_slow_path(func == NULL)) {
                 return NJS_TOKEN_ERROR;
@@ -912,39 +912,44 @@ njs_parser_call_expression(njs_vm_t *vm, njs_parser_t *parser,
             func->token = NJS_TOKEN_FUNCTION_CALL;
             func->left = node;
             func->index = node->index;
-            parser->code_size += sizeof(njs_vmcode_function_t)
-                                 + sizeof(njs_vmcode_call_t);
+            parser->code_size += sizeof(njs_vmcode_function_frame_t)
+                                 + sizeof(njs_vmcode_function_call_t);
             break;
 
-        case NJS_TOKEN_OBJECT_CONSTRUCTOR:
-        case NJS_TOKEN_ARRAY_CONSTRUCTOR:
-        case NJS_TOKEN_BOOLEAN_CONSTRUCTOR:
-        case NJS_TOKEN_NUMBER_CONSTRUCTOR:
-        case NJS_TOKEN_STRING_CONSTRUCTOR:
-        case NJS_TOKEN_FUNCTION_CONSTRUCTOR:
-        case NJS_TOKEN_REGEXP_CONSTRUCTOR:
-        case NJS_TOKEN_EVAL:
+        case NJS_TOKEN_PROPERTY:
             func = njs_parser_node_alloc(vm);
             if (nxt_slow_path(func == NULL)) {
                 return NJS_TOKEN_ERROR;
             }
 
-            func->token = NJS_TOKEN_FUNCTION_CALL;
+            func->token = NJS_TOKEN_METHOD_CALL;
             func->left = node;
-            parser->code_size += sizeof(njs_vmcode_method_t)
-                                 + sizeof(njs_vmcode_call_t);
+            parser->code_size += sizeof(njs_vmcode_method_frame_t)
+                                 + sizeof(njs_vmcode_function_call_t);
             break;
 
         default:
+            /*
+             * NJS_TOKEN_OPEN_PARENTHESIS,
+             * NJS_TOKEN_OBJECT_CONSTRUCTOR,
+             * NJS_TOKEN_ARRAY_CONSTRUCTOR,
+             * NJS_TOKEN_BOOLEAN_CONSTRUCTOR,
+             * NJS_TOKEN_NUMBER_CONSTRUCTOR,
+             * NJS_TOKEN_STRING_CONSTRUCTOR,
+             * NJS_TOKEN_FUNCTION_CONSTRUCTOR,
+             * NJS_TOKEN_REGEXP_CONSTRUCTOR,
+             * NJS_TOKEN_EVAL.
+             */
             func = njs_parser_node_alloc(vm);
             if (nxt_slow_path(func == NULL)) {
                 return NJS_TOKEN_ERROR;
             }
 
-            func->token = NJS_TOKEN_METHOD_CALL;
+            func->token = NJS_TOKEN_FUNCTION_CALL;
             func->left = node;
-            parser->code_size += sizeof(njs_vmcode_method_t)
-                                 + sizeof(njs_vmcode_call_t);
+            parser->code_size += sizeof(njs_vmcode_function_frame_t)
+                                 + sizeof(njs_vmcode_function_call_t);
+            break;
         }
 
         token = njs_parser_arguments(vm, parser, func);
@@ -1064,7 +1069,6 @@ njs_parser_arguments(njs_vm_t *vm, njs_parser_t *parser,
     njs_index_t        index;
     njs_parser_node_t  *node;
 
-    parser->nesting_arguments++;
     index = NJS_SCOPE_CALLEE_ARGUMENTS;
 
     do {
@@ -1104,21 +1108,5 @@ njs_parser_arguments(njs_vm_t *vm, njs_parser_t *parser,
         return NJS_TOKEN_ILLEGAL;
     }
 
-    index = njs_index_size(index);
-    index += NJS_NATIVE_FRAME_SIZE + sizeof(njs_value_t);
-
-    parser->nesting_arguments_size += index;
-
-    parser->nesting_arguments--;
-
-    if (parser->nesting_arguments == 0) {
-
-        if (parser->method_arguments_size < parser->nesting_arguments_size) {
-            parser->method_arguments_size = parser->nesting_arguments_size;
-        }
-
-        parser->nesting_arguments_size = 0;
-    }
-
     return token;
 }
index ae99d4543816e7038db3ab2c4c4e0bea7a105d7e..3b30a0318bf8e087223744d4f41ceadfc737bd63 100644 (file)
@@ -81,8 +81,20 @@ static nxt_noinline njs_ret_t njs_values_compare(njs_value_t *val1,
     njs_value_t *val2);
 static nxt_noinline nxt_bool_t njs_values_strict_equal(njs_value_t *val1,
     njs_value_t *val2);
+static nxt_noinline njs_ret_t njs_function_frame_free(njs_vm_t *vm,
+    njs_native_frame_t *frame, njs_native_frame_t *skip);
+
+static njs_ret_t njs_vmcode_number_primitive(njs_vm_t *vm, njs_value_t *invld,
+    njs_value_t *narg);
+static njs_ret_t njs_vmcode_string_primitive(njs_vm_t *vm, njs_value_t *invld,
+    njs_value_t *narg);
 static njs_ret_t njs_primitive_value(njs_vm_t *vm, njs_value_t *value,
     nxt_uint_t hint);
+static njs_ret_t njs_vm_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1,
+    njs_value_t *value2);
+static njs_ret_t njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1,
+    njs_value_t *invld2);
+
 void njs_debug(njs_index_t index, njs_value_t *value);
 
 
@@ -147,7 +159,9 @@ njs_vmcode_interpreter(njs_vm_t *vm)
              *   njs_vmcode_if_true_jump(),
              *   njs_vmcode_if_false_jump(),
              *   njs_vmcode_validate(),
-             *   njs_vmcode_call(),
+             *   njs_vmcode_function_frame(),
+             *   njs_vmcode_method_frame(),
+             *   njs_vmcode_function_call(),
              *   njs_vmcode_return(),
              *   njs_vmcode_try_start(),
              *   njs_vmcode_try_next(),
@@ -203,7 +217,7 @@ njs_vmcode_interpreter(njs_vm_t *vm)
         case NJS_TRAP_INCDEC:
         case NJS_TRAP_PROPERTY:
 
-            ret = njs_vmcode_trap(vm, ret - NJS_TRAP_LAST, value1, value2);
+            ret = njs_vm_trap(vm, ret - NJS_TRAP_LAST, value1, value2);
 
             if (nxt_fast_path(ret == NXT_OK)) {
                 goto again;
@@ -220,7 +234,7 @@ njs_vmcode_interpreter(njs_vm_t *vm)
 
             for ( ;; ) {
                 frame = (njs_frame_t *) vm->frame;
-                catch = frame->native.u.exception.catch;
+                catch = frame->native.exception.catch;
 
                 if (catch != NULL) {
                     vm->current = catch;
@@ -240,7 +254,7 @@ njs_vmcode_interpreter(njs_vm_t *vm)
                 vm->scopes[NJS_SCOPE_LOCAL] = frame->prev_local;
                 vm->scopes[NJS_SCOPE_ARGUMENTS] = frame->prev_arguments;
 
-                if (frame->native.start) {
+                if (frame->native.first) {
                     nxt_mem_cache_free(vm->mem_cache_pool, frame);
                 }
             }
@@ -309,7 +323,7 @@ njs_value_release(njs_vm_t *vm, njs_value_t *value)
 
 
 njs_ret_t
-njs_vmcode_object_create(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+njs_vmcode_object(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
 {
     njs_object_t  *object;
 
@@ -328,7 +342,7 @@ njs_vmcode_object_create(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
 
 
 njs_ret_t
-njs_vmcode_array_create(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+njs_vmcode_array(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
 {
     uint32_t            size;
     njs_array_t         *array;
@@ -361,26 +375,25 @@ njs_vmcode_array_create(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
 
 
 njs_ret_t
-njs_vmcode_function_create(njs_vm_t *vm, njs_value_t *invld1,
+njs_vmcode_function(njs_vm_t *vm, njs_value_t *invld1,
     njs_value_t *invld2)
 {
-    njs_function_t                *func;
-    njs_vmcode_function_create_t  *code;
+    njs_function_t         *function;
+    njs_vmcode_function_t  *code;
 
-    func = nxt_mem_cache_zalign(vm->mem_cache_pool, sizeof(njs_value_t),
-                                sizeof(njs_function_t));
+    function = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_function_t));
 
-    if (nxt_fast_path(func != NULL)) {
-        func->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION];
-        func->args_offset = 1;
+    if (nxt_fast_path(function != NULL)) {
+        function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION];
+        function->args_offset = 1;
 
-        code = (njs_vmcode_function_create_t *) vm->current;
-        func->code.script = code->function;
-        vm->retval.data.u.function = func;
+        code = (njs_vmcode_function_t *) vm->current;
+        function->u.lambda = code->lambda;
+        vm->retval.data.u.function = function;
         vm->retval.type = NJS_FUNCTION;
         vm->retval.data.truth = 1;
 
-        return sizeof(njs_vmcode_function_create_t);
+        return sizeof(njs_vmcode_function_t);
     }
 
     return NXT_ERROR;
@@ -388,7 +401,7 @@ njs_vmcode_function_create(njs_vm_t *vm, njs_value_t *invld1,
 
 
 njs_ret_t
-njs_vmcode_regexp_create(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
 {
     njs_regexp_t         *regexp;
     njs_vmcode_regexp_t  *code;
@@ -2042,29 +2055,30 @@ njs_vmcode_if_false_jump(njs_vm_t *vm, njs_value_t *cond, njs_value_t *offset)
 
 
 njs_ret_t
-njs_vmcode_function(njs_vm_t *vm, njs_value_t *name, njs_value_t *invld)
+njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *invld, njs_value_t *name)
 {
-    njs_ret_t              ret;
-    njs_value_t            value, *this;
-    njs_param_t            param;
-    njs_object_t           *object;
-    njs_function_t         *function;
-    njs_vmcode_function_t  *func;
+    njs_ret_t                    ret;
+    njs_value_t                  val, *this, *value;
+    njs_param_t                  param;
+    njs_object_t                 *object;
+    njs_function_t               *function;
+    njs_vmcode_function_frame_t  *func;
+
+    value = njs_vmcode_operand(vm, name);
 
-    if (nxt_fast_path(njs_is_function(name))) {
+    if (nxt_fast_path(njs_is_function(value))) {
 
-        func = (njs_vmcode_function_t *) vm->current;
+        func = (njs_vmcode_function_frame_t *) vm->current;
 
-        function = name->data.u.function;
+        function = value->data.u.function;
 
         if (function->native) {
-            this = njs_vmcode_native_frame(vm, &vm->retval, func->code.nargs,
-                                           func->code.ctor);
+            this = njs_function_native_frame(vm, function->u.native, 0,
+                                             &func->code);
             if (nxt_fast_path(this != NULL)) {
                 *this = njs_value_void;
-                vm->retval = *name;
 
-                return sizeof(njs_vmcode_function_t);
+                return sizeof(njs_vmcode_function_frame_t);
             }
 
             return NXT_ERROR;
@@ -2077,10 +2091,10 @@ njs_vmcode_function(njs_vm_t *vm, njs_value_t *name, njs_value_t *invld)
                 return NXT_ERROR;
             }
 
-            value.data.u.object = object;
-            value.type = NJS_OBJECT;
-            value.data.truth = 1;
-            param.object = &value;
+            val.data.u.object = object;
+            val.type = NJS_OBJECT;
+            val.data.truth = 1;
+            param.object = &val;
 
         } else {
             param.object = (njs_value_t *) &njs_value_void;
@@ -2089,34 +2103,34 @@ njs_vmcode_function(njs_vm_t *vm, njs_value_t *name, njs_value_t *invld)
         param.args = NULL;
         param.nargs = func->code.nargs;
 
-        ret = njs_vmcode_function_frame(vm, name, &param, func->code.ctor);
+        ret = njs_function_frame(vm, function, &param, func->code.ctor);
 
         if (nxt_fast_path(ret == NXT_OK)) {
-            return sizeof(njs_vmcode_function_t);
+            return sizeof(njs_vmcode_function_frame_t);
         }
 
-    } else {
-        vm->exception = &njs_exception_type_error;
+        return ret;
     }
 
+    vm->exception = &njs_exception_type_error;
+
     return NXT_ERROR;
 }
 
 
 njs_ret_t
-njs_vmcode_method(njs_vm_t *vm, njs_value_t *object, njs_value_t *name)
+njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *name, njs_value_t *object)
 {
-    uintptr_t             nargs;
-    njs_ret_t             ret;
-    njs_value_t           *this;
-    njs_param_t           param;
-    njs_extern_t          *ext;
-    njs_object_prop_t     *prop;
-    njs_vmcode_method_t   *method;
-    njs_property_query_t  pq;
+    njs_ret_t                  ret;
+    njs_value_t                *this;
+    njs_param_t                param;
+    njs_extern_t               *ext;
+    njs_function_t             *function;
+    njs_object_prop_t          *prop;
+    njs_property_query_t       pq;
+    njs_vmcode_method_frame_t  *method;
 
-    method = (njs_vmcode_method_t *) vm->current;
-    nargs = method->code.nargs;
+    object = njs_vmcode_operand(vm, object);
 
     pq.query = NJS_PROPERTY_QUERY_GET;
 
@@ -2125,36 +2139,40 @@ njs_vmcode_method(njs_vm_t *vm, njs_value_t *object, njs_value_t *name)
     case NXT_OK:
         prop = pq.lhq.value;
 
-        if (njs_is_function(&prop->value)
-            && !prop->value.data.u.function->native)
-        {
-            param.object = object;
-            param.args = NULL;
-            param.nargs = nargs;
+        if (njs_is_function(&prop->value)) {
 
-            ret = njs_vmcode_function_frame(vm, &prop->value, &param,
-                                            method->code.ctor);
+            method = (njs_vmcode_method_frame_t *) vm->current;
+            function = prop->value.data.u.function;
 
-            if (nxt_fast_path(ret == NXT_OK)) {
-                return sizeof(njs_vmcode_method_t);
-            }
+            if (!function->native) {
+                param.object = object;
+                param.args = NULL;
+                param.nargs = method->code.nargs;
 
-            return ret;
-        }
+                ret = njs_function_frame(vm, function, &param,
+                                         method->code.ctor);
+
+                if (nxt_fast_path(ret == NXT_OK)) {
+                    return sizeof(njs_vmcode_method_frame_t);
+                }
+
+                return ret;
+            }
 
-        vm->retval = prop->value;
+            this = njs_function_native_frame(vm, function->u.native,
+                                             prop->value.data.string_size,
+                                             &method->code);
+            if (nxt_slow_path(this == NULL)) {
+                return NXT_ERROR;
+            }
 
-        njs_retain(object);
+            njs_retain(object);
+            *this = *object;
 
-        this = njs_vmcode_native_frame(vm, &vm->retval, nargs,
-                                       method->code.ctor);
-        if (nxt_slow_path(this == NULL)) {
-            return NXT_ERROR;
+            return sizeof(njs_vmcode_method_frame_t);
         }
 
-        *this = *object;
-
-        return sizeof(njs_vmcode_method_t);
+        break;
 
     case NJS_EXTERNAL_VALUE:
         ext = object->data.u.external;
@@ -2162,16 +2180,12 @@ njs_vmcode_method(njs_vm_t *vm, njs_value_t *object, njs_value_t *name)
         ret = nxt_lvlhsh_find(&ext->hash, &pq.lhq);
 
         if (ret == NXT_OK) {
+            method = (njs_vmcode_method_frame_t *) vm->current;
             ext = pq.lhq.value;
 
             if (ext->type == NJS_EXTERN_METHOD) {
-                vm->retval.type = NJS_NATIVE;
-                vm->retval.data.truth = 1;
-                vm->retval.data.string_size = 0;
-                vm->retval.data.u.method = ext->method;
-
-                this = njs_vmcode_native_frame(vm, &vm->retval, nargs,
-                                               method->code.ctor);
+                this = njs_function_native_frame(vm, ext->method, 0,
+                                                 &method->code);
 
                 if (nxt_slow_path(this == NULL)) {
                     return NXT_ERROR;
@@ -2179,44 +2193,37 @@ njs_vmcode_method(njs_vm_t *vm, njs_value_t *object, njs_value_t *name)
 
                 this->data.u.data = vm->external[ext->object];
 
-                return sizeof(njs_vmcode_method_t);
+                return sizeof(njs_vmcode_method_frame_t);
             }
         }
 
-        /* Fall through. */
+        break;
 
     default:
-        vm->exception = &njs_exception_type_error;
-        return NXT_ERROR;
+        break;
     }
+
+    vm->exception = &njs_exception_type_error;
+
+    return NXT_ERROR;
 }
 
 
 njs_ret_t
-njs_vmcode_call(njs_vm_t *vm, njs_value_t *func, njs_value_t *retval)
+njs_vmcode_function_call(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
 {
-    njs_ret_t          ret;
-    njs_value_t        *args;
-    njs_param_t        param;
-    njs_native_t       native;
-    njs_function_t     *function;
-    njs_vmcode_call_t  *call;
-
-    call = (njs_vmcode_call_t *) vm->current;
-    vm->current += sizeof(njs_vmcode_call_t);
+    njs_ret_t                   ret;
+    njs_value_t                 *args;
+    njs_param_t                 param;
+    njs_native_frame_t          *frame, *previous, *skip;
+    njs_vmcode_function_call_t  *call;
 
-    if (njs_is_function(func)) {
-        function = func->data.u.function;
+    call = (njs_vmcode_function_call_t *) vm->current;
+    vm->current += sizeof(njs_vmcode_function_call_t);
 
-        if (!function->native) {
-            (void) njs_function_call(vm, function, (njs_index_t) retval);
-            return 0;
-        }
-
-        native = function->code.native;
-
-    } else {
-        native = func->data.u.method;
+    if (!vm->frame->native) {
+        (void) njs_function_call(vm, (njs_index_t) retval);
+        return 0;
     }
 
     param.retval = (njs_index_t) retval;
@@ -2225,7 +2232,7 @@ njs_vmcode_call(njs_vm_t *vm, njs_value_t *func, njs_value_t *retval)
     param.args = args;
     param.object = args - 1;
 
-    ret = native(vm, &param);
+    ret = vm->frame->u.native(vm, &param);
     /*
      * A native method can return:
      *    NXT_OK on method success;
@@ -2236,11 +2243,27 @@ njs_vmcode_call(njs_vm_t *vm, njs_value_t *func, njs_value_t *retval)
      * The callee arguments must be preserved for NJS_PASS and NXT_AGAIN cases.
      */
     if (ret == NXT_OK) {
+        skip = NULL;
+        frame = vm->frame;
+        previous = frame->previous;
+
+        if (previous->skip) {
+
+            if (previous->first) {
+                skip = previous;
+            }
+
+            previous = previous->previous;
+        }
+
+        vm->frame = previous;
+
+        (void) njs_function_frame_free(vm, frame, skip);
+
         /*
          * If a retval is in a callee arguments scope it
          * must be in the previous callee arguments scope.
          */
-        vm->frame = vm->frame->previous;
         vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = vm->frame->arguments;
 
         retval = njs_vmcode_operand(vm, retval);
@@ -2267,7 +2290,7 @@ njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
     njs_value_t         *value;
     njs_frame_t         *frame;
     njs_value_t         *args;
-    njs_native_frame_t  *previous;
+    njs_native_frame_t  *previous, *skip;
 
     value = njs_vmcode_operand(vm, retval);
 
@@ -2282,7 +2305,18 @@ njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
         }
     }
 
+    skip = NULL;
     previous = frame->native.previous;
+
+    if (previous->skip) {
+
+        if (previous->first) {
+            skip = previous;
+        }
+
+        previous = previous->previous;
+    }
+
     vm->frame = previous;
 
     vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = previous->arguments;
@@ -2299,16 +2333,28 @@ njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
     /* GC: value external/internal++ depending on value and retval type */
     *retval = *value;
 
-    vm->current = frame->return_address;
+    vm->current = frame->native.u.return_address;
 
     /* GC: arguments and local. */
 
     njs_release(vm, &args[0]);
 
-    if (frame->native.start) {
+    return njs_function_frame_free(vm, &frame->native, skip);
+}
+
+
+static nxt_noinline njs_ret_t
+njs_function_frame_free(njs_vm_t *vm, njs_native_frame_t *frame,
+    njs_native_frame_t *skip)
+{
+    if (frame->first) {
         nxt_mem_cache_free(vm->mem_cache_pool, frame);
     }
 
+    if (skip != NULL) {
+        nxt_mem_cache_free(vm->mem_cache_pool, skip);
+    }
+
     return 0;
 }
 
@@ -2337,17 +2383,17 @@ njs_vmcode_try_start(njs_vm_t *vm, njs_value_t *value, njs_value_t *offset)
 {
     njs_exception_t  *e;
 
-    if (vm->frame->u.exception.catch != NULL) {
+    if (vm->frame->exception.catch != NULL) {
         e = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_exception_t));
         if (nxt_slow_path(e == NULL)) {
             return NXT_ERROR;
         }
 
-        *e = vm->frame->u.exception;
-        vm->frame->u.exception.next = e;
+        *e = vm->frame->exception;
+        vm->frame->exception.next = e;
     }
 
-    vm->frame->u.exception.catch = vm->current + (njs_ret_t) offset;
+    vm->frame->exception.catch = vm->current + (njs_ret_t) offset;
 
     njs_set_invalid(value);
 
@@ -2365,13 +2411,13 @@ njs_vmcode_try_end(njs_vm_t *vm, njs_value_t *invld, njs_value_t *offset)
 {
     njs_exception_t  *e;
 
-    e = vm->frame->u.exception.next;
+    e = vm->frame->exception.next;
 
     if (e == NULL) {
-        vm->frame->u.exception.catch = NULL;
+        vm->frame->exception.catch = NULL;
 
     } else {
-        vm->frame->u.exception = *e;
+        vm->frame->exception = *e;
         nxt_mem_cache_free(vm->mem_cache_pool, e);
     }
 
@@ -2409,7 +2455,7 @@ njs_vmcode_catch(njs_vm_t *vm, njs_value_t *exception, njs_value_t *offset)
         return njs_vmcode_try_end(vm, exception, offset);
     }
 
-    vm->frame->u.exception.catch = vm->current + (njs_ret_t) offset;
+    vm->frame->exception.catch = vm->current + (njs_ret_t) offset;
 
     return sizeof(njs_vmcode_catch_t);
 }
@@ -2606,7 +2652,94 @@ njs_primitive_value(njs_vm_t *vm, njs_value_t *value, nxt_uint_t hint)
 }
 
 
-njs_ret_t
+static const njs_vmcode_1addr_t  njs_trap_strings[] = {
+    { .code = { .operation = njs_vmcode_string_primitive,
+                .operands =  NJS_VMCODE_1OPERAND,
+                .retval = NJS_VMCODE_NO_RETVAL },
+      .index = 0 },
+    { .code = { .operation = njs_vmcode_string_primitive,
+                .operands =  NJS_VMCODE_1OPERAND,
+                .retval = NJS_VMCODE_NO_RETVAL },
+      .index = 1 },
+    { .code = { .operation = njs_vmcode_restart,
+                .operands =  NJS_VMCODE_NO_OPERAND,
+                .retval = NJS_VMCODE_NO_RETVAL } },
+};
+
+
+static const njs_vmcode_1addr_t  njs_trap_numbers[] = {
+    { .code = { .operation = njs_vmcode_number_primitive,
+                .operands =  NJS_VMCODE_1OPERAND,
+                .retval = NJS_VMCODE_NO_RETVAL },
+      .index = 0 },
+    { .code = { .operation = njs_vmcode_number_primitive,
+                .operands =  NJS_VMCODE_1OPERAND,
+                .retval = NJS_VMCODE_NO_RETVAL },
+      .index = 1 },
+    { .code = { .operation = njs_vmcode_restart,
+                .operands =  NJS_VMCODE_NO_OPERAND,
+                .retval = NJS_VMCODE_NO_RETVAL } },
+};
+
+
+static const njs_vmcode_1addr_t  njs_trap_number[] = {
+    { .code = { .operation = njs_vmcode_number_primitive,
+                .operands =  NJS_VMCODE_1OPERAND,
+                .retval = NJS_VMCODE_NO_RETVAL },
+      .index = 0 },
+    { .code = { .operation = njs_vmcode_restart,
+                .operands =  NJS_VMCODE_NO_OPERAND,
+                .retval = NJS_VMCODE_NO_RETVAL } },
+};
+
+
+static const njs_vm_trap_t  njs_vm_traps[] = {
+    /* NJS_TRAP_PROPERTY */  { &njs_trap_strings[1], 0 },
+    /* NJS_TRAP_STRINGS */   { &njs_trap_strings[0], 0 },
+    /* NJS_TRAP_INCDEC */    { &njs_trap_numbers[1], 1 },
+    /* NJS_TRAP_NUMBERS */   { &njs_trap_numbers[0], 0 },
+    /* NJS_TRAP_NUMBER */    { &njs_trap_number[0],  0 },
+};
+
+
+static njs_ret_t
+njs_vm_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1,
+    njs_value_t *value2)
+{
+    size_t              size;
+    njs_value_t         *values;
+    njs_native_frame_t  *frame;
+
+    size = NJS_NATIVE_FRAME_SIZE + 3 * sizeof(njs_value_t);
+
+    frame = njs_function_frame_alloc(vm, size);
+    if (nxt_slow_path(frame == NULL)) {
+        return NXT_ERROR;
+    }
+
+    frame->ctor = 0;
+
+    values = njs_native_data(frame);
+    njs_set_invalid(&values[0]);
+    values[2] = *value2;
+
+    frame->trap_reference = njs_vm_traps[trap].reference_value;
+
+    if (njs_vm_traps[trap].reference_value) {
+        values[1].data.u.value = value1;
+
+    } else {
+        values[1] = *value1;
+    }
+
+    frame->u.restart = vm->current;
+    vm->current = (u_char *) njs_vm_traps[trap].code;
+
+    return NXT_OK;
+}
+
+
+static njs_ret_t
 njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
 {
     u_char                *restart;
@@ -2638,7 +2771,7 @@ njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
 
     *retval = vm->retval;
 
-    if (frame->start) {
+    if (frame->first) {
         nxt_mem_cache_free(vm->mem_cache_pool, frame);
     }
 
index 133feeafff98cc6a51fd1877bac034a03f604151..3ba172106924e74bb7cbb1a4d0b7fac4c9d07748 100644 (file)
@@ -82,7 +82,7 @@ typedef struct njs_string_s           njs_string_t;
 typedef struct njs_object_init_s      njs_object_init_t;
 typedef struct njs_object_value_s     njs_object_value_t;
 typedef struct njs_array_s            njs_array_t;
-typedef struct njs_function_script_s  njs_function_script_t;
+typedef struct njs_function_lambda_s  njs_function_lambda_t;
 typedef struct njs_regexp_s           njs_regexp_t;
 typedef struct njs_regexp_pattern_s   njs_regexp_pattern_t;
 typedef struct njs_extern_s           njs_extern_t;
@@ -115,9 +115,9 @@ typedef struct {
 #endif
 
     union {
-        njs_function_script_t         *script;
+        njs_function_lambda_t         *lambda;
         njs_native_t                  native;
-    } code;
+    } u;
 
     njs_value_t                       *args;
 } njs_function_t;
@@ -139,7 +139,7 @@ union njs_value_s {
      * the maximum size of short string to 13.
      */
     struct {
-        njs_value_type_t          type:8;  /* 4 bits */
+        njs_value_type_t              type:8;  /* 4 bits */
         /*
          * The truth field is set during value assignment and then can be
          * quickly tested by logical and conditional operations regardless
@@ -147,44 +147,49 @@ union njs_value_s {
          * and short_string.length so when string size and length are zero
          * the string's value is false.
          */
-        uint8_t                   truth;
+        uint8_t                       truth;
 
         /* 0xff if u.data.string is external string. */
-        uint8_t                   external0;
-        uint8_t                   _spare;
+        uint8_t                       external0;
+        uint8_t                       _spare;
 
-        /* A long string size. */
-        uint32_t                  string_size;
+        /*
+         * A long string size.
+         * Besides this field is used in native reentrant methods to
+         * store size of local state data allocated on stack frame.
+         */
+        uint32_t                      string_size;
 
         union {
-            double                number;
-            njs_string_t          *string;
-            njs_object_t          *object;
-            njs_array_t           *array;
-            njs_object_value_t    *object_value;
-            njs_function_t        *function;
-            njs_regexp_t          *regexp;
-            njs_getter_t          getter;
-            njs_native_t          method;
-            njs_extern_t          *external;
-            njs_value_t           *value;
-            void                  *data;
+            double                     number;
+            njs_string_t               *string;
+            njs_object_t               *object;
+            njs_array_t                *array;
+            njs_object_value_t         *object_value;
+            njs_function_t             *function;
+            njs_function_lambda_t      *lambda;
+            njs_regexp_t               *regexp;
+            njs_getter_t               getter;
+            njs_native_t               method;
+            njs_extern_t               *external;
+            njs_value_t                *value;
+            void                       *data;
         } u;
     } data;
 
     struct {
-        njs_value_type_t          type:8;  /* 4 bits */
+        njs_value_type_t              type:8;  /* 4 bits */
 
-#define NJS_STRING_SHORT          14
-#define NJS_STRING_LONG           15
+#define NJS_STRING_SHORT              14
+#define NJS_STRING_LONG               15
 
-        uint8_t                   size:4;
-        uint8_t                   length:4;
+        uint8_t                       size:4;
+        uint8_t                       length:4;
 
-        u_char                    start[NJS_STRING_SHORT];
+        u_char                        start[NJS_STRING_SHORT];
     } short_string;
 
-    njs_value_type_t              type:8;  /* 4 bits */
+    njs_value_type_t                  type:8;  /* 4 bits */
 };
 
 
@@ -230,7 +235,7 @@ union njs_value_s {
         .u.function = & (njs_function_t) {                                    \
             .native = 1,                                                      \
             .args_offset = 1,                                                 \
-            .code.native = _function,                                         \
+            .u.native = _function,                                            \
         }                                                                     \
     }                                                                         \
 }
@@ -243,14 +248,6 @@ union njs_value_s {
     } }
 
 
-#define njs_method(_method, _size)                                            \
-    { .data = { .type = NJS_NATIVE,                                           \
-                .truth = 1,                                                   \
-                .string_size = _size,                                         \
-                .u = { .method = _method }                                    \
-    } }
-
-
 typedef njs_ret_t (*njs_vmcode_operation_t)(njs_vm_t *vm, njs_value_t *value1,
     njs_value_t *value2);
 
@@ -408,12 +405,6 @@ typedef struct {
 } njs_vmcode_3addr_t;
 
 
-typedef struct {
-    njs_vmcode_t               code;
-    njs_index_t                retval;
-} njs_vmcode_stop_t;
-
-
 typedef struct {
     njs_vmcode_t               code;
     njs_index_t                index;
@@ -443,8 +434,8 @@ typedef struct {
 typedef struct {
     njs_vmcode_t               code;
     njs_index_t                retval;
-    njs_function_script_t      *function;
-} njs_vmcode_function_create_t;
+    njs_function_lambda_t      *lambda;
+} njs_vmcode_function_t;
 
 
 typedef struct {
@@ -510,24 +501,33 @@ typedef struct {
 
 typedef struct {
     njs_vmcode_t               code;
-    njs_index_t                function;
     njs_index_t                name;
-} njs_vmcode_function_t;
+} njs_vmcode_function_frame_t;
 
 
 typedef struct {
     njs_vmcode_t               code;
-    njs_index_t                function;
     njs_index_t                object;
     njs_index_t                method;
-} njs_vmcode_method_t;
+} njs_vmcode_method_frame_t;
 
 
 typedef struct {
     njs_vmcode_t               code;
     njs_index_t                retval;
-    njs_index_t                function;
-} njs_vmcode_call_t;
+} njs_vmcode_function_call_t;
+
+
+typedef struct {
+    njs_vmcode_t               code;
+    njs_index_t                retval;
+} njs_vmcode_return_t;
+
+
+typedef struct {
+    njs_vmcode_t               code;
+    njs_index_t                retval;
+} njs_vmcode_stop_t;
 
 
 typedef struct {
@@ -717,13 +717,13 @@ nxt_int_t njs_vmcode_interpreter(njs_vm_t *vm);
 void njs_value_retain(njs_value_t *value);
 void njs_value_release(njs_vm_t *vm, njs_value_t *value);
 
-njs_ret_t njs_vmcode_object_create(njs_vm_t *vm, njs_value_t *inlvd1,
+njs_ret_t njs_vmcode_object(njs_vm_t *vm, njs_value_t *inlvd1,
     njs_value_t *inlvd2);
-njs_ret_t njs_vmcode_array_create(njs_vm_t *vm, njs_value_t *inlvd1,
+njs_ret_t njs_vmcode_array(njs_vm_t *vm, njs_value_t *inlvd1,
     njs_value_t *inlvd2);
-njs_ret_t njs_vmcode_function_create(njs_vm_t *vm, njs_value_t *inlvd1,
+njs_ret_t njs_vmcode_function(njs_vm_t *vm, njs_value_t *inlvd1,
     njs_value_t *invld2);
-njs_ret_t njs_vmcode_regexp_create(njs_vm_t *vm, njs_value_t *inlvd1,
+njs_ret_t njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *inlvd1,
     njs_value_t *invld2);
 
 njs_ret_t njs_vmcode_property_get(njs_vm_t *vm, njs_value_t *object,
@@ -815,11 +815,12 @@ njs_ret_t njs_vmcode_if_true_jump(njs_vm_t *vm, njs_value_t *cond,
 njs_ret_t njs_vmcode_if_false_jump(njs_vm_t *vm, njs_value_t *cond,
     njs_value_t *offset);
 
-njs_ret_t njs_vmcode_function(njs_vm_t *vm, njs_value_t *name,
-    njs_value_t *invld);
-njs_ret_t njs_vmcode_method(njs_vm_t *vm, njs_value_t *object,
+njs_ret_t njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *invld,
+    njs_value_t *name);
+njs_ret_t njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object,
     njs_value_t *method);
-njs_ret_t njs_vmcode_call(njs_vm_t *vm, njs_value_t *func, njs_value_t *retval);
+njs_ret_t njs_vmcode_function_call(njs_vm_t *vm, njs_value_t *invld,
+    njs_value_t *retval);
 njs_ret_t njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld,
     njs_value_t *retval);
 njs_ret_t njs_vmcode_stop(njs_vm_t *vm, njs_value_t *invld,
@@ -836,14 +837,7 @@ njs_ret_t njs_vmcode_catch(njs_vm_t *vm, njs_value_t *invld,
 njs_ret_t njs_vmcode_finally(njs_vm_t *vm, njs_value_t *invld,
     njs_value_t *retval);
 
-njs_ret_t njs_vmcode_number_primitive(njs_vm_t *vm, njs_value_t *invld,
-    njs_value_t *narg);
-njs_ret_t njs_vmcode_string_primitive(njs_vm_t *vm, njs_value_t *invld,
-    njs_value_t *narg);
-njs_ret_t njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1,
-    njs_value_t *invld2);
-
-nxt_noinline void njs_number_set(njs_value_t *value, double num);
+void njs_number_set(njs_value_t *value, double num);
 
 nxt_int_t njs_builtin_objects_create(njs_vm_t *vm);
 nxt_int_t njs_builtin_objects_clone(njs_vm_t *vm);
index 49eef4b0a1c3321b534bc899930fa604392c6b6b..9825dd6e11076c65ab505af3780b56164af6bbe2 100644 (file)
@@ -218,7 +218,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end)
 
     *start = parser->lexer->start;
 
-    ret = njs_generate_scope(vm, parser, node, njs_vmcode_stop);
+    ret = njs_generate_scope(vm, parser, node);
     if (nxt_slow_path(ret != NXT_OK)) {
         return NJS_ERROR;
     }
@@ -288,20 +288,20 @@ njs_vm_clone(njs_vm_t *vm, nxt_mem_cache_pool_t *mcp, void **external)
 
         frame->native.previous = NULL;
         frame->native.arguments = NULL;
-        frame->native.start = 1;
+        frame->native.first = 1;
 
-        frame->native.u.exception.next = NULL;
-        frame->native.u.exception.catch = NULL;
+        frame->native.exception.next = NULL;
+        frame->native.exception.catch = NULL;
 
         frame->prev_arguments = NULL;
         frame->local = NULL;
         frame->closure = NULL;
 
-        frame->native.size = size - (NJS_GLOBAL_FRAME_SIZE + scope_size);
+        frame->native.free_size = size - (NJS_GLOBAL_FRAME_SIZE + scope_size);
 
         values = (u_char *) frame + NJS_GLOBAL_FRAME_SIZE;
 
-        frame->native.last = values + scope_size;
+        frame->native.free = values + scope_size;
 
         nvm->scopes[NJS_SCOPE_GLOBAL] = (njs_value_t *) values;
         memcpy(values + NJS_INDEX_GLOBAL_OFFSET, vm->global_scope,
@@ -374,10 +374,10 @@ njs_vm_run(njs_vm_t *vm)
 }
 
 
-void
-njs_vm_return(njs_vm_t *vm, njs_value_t *retval)
+njs_ret_t
+njs_vm_return_string(njs_vm_t *vm, u_char *start, size_t size)
 {
-    vm->retval = *retval;
+    return njs_string_create(vm, &vm->retval, start, size, 0);
 }
 
 
index 7e9de7db87228c7a7cc8edd7945b69355abbd272..8cd238a6484eb87aca5571cc5b6f957154c9e732 100644 (file)
@@ -88,7 +88,8 @@ NXT_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, nxt_mem_cache_pool_t *mcp,
     void **external);
 NXT_EXPORT nxt_int_t njs_vm_run(njs_vm_t *vm);
 
-NXT_EXPORT void njs_vm_return(njs_vm_t *vm, njs_value_t *retval);
+NXT_EXPORT njs_ret_t njs_vm_return_string(njs_vm_t *vm, u_char *start,
+    size_t size);
 NXT_EXPORT nxt_int_t njs_vm_retval(njs_vm_t *vm, nxt_str_t *retval);
 NXT_EXPORT nxt_int_t njs_vm_exception(njs_vm_t *vm, nxt_str_t *retval);
 
index facd48a56bbbd7a3e2d3f8db89e036de9b4afe78..a9f50eb9a9c6830281e83a8d698490b04e741622 100644 (file)
@@ -1381,9 +1381,6 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("typeof /./i"),
       nxt_string("object") },
 
-    { nxt_string("typeof $r"),
-      nxt_string("undefined") },
-
     { nxt_string("typeof a"),
       nxt_string("undefined") },
 
@@ -2003,44 +2000,6 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("a = '\\xB5\\xA7\\xB1\\xAE'.toBytes(); a.fromBytes(1, 3)"),
       nxt_string("§±") },
 
-    { nxt_string("a = $r.uri; s = a.fromUTF8(); s.length +' '+ s"),
-      nxt_string("3 АБВ") },
-
-    { nxt_string("a = $r.uri; s = a.fromUTF8(2); s.length +' '+ s"),
-      nxt_string("2 БВ") },
-
-    { nxt_string("a = $r.uri; s = a.fromUTF8(2, 4); s.length +' '+ s"),
-      nxt_string("1 Б") },
-
-    { nxt_string("a = $r.uri; a +' '+ a.length +' '+ a"),
-      nxt_string("АБВ 6 АБВ") },
-
-    { nxt_string("$r.uri = 'αβγ'; a = $r.uri; a.length +' '+ a"),
-      nxt_string("6 αβγ") },
-
-    { nxt_string("$r.uri.length +' '+ $r.uri"),
-      nxt_string("6 АБВ") },
-
-    { nxt_string("$r.uri = $r.uri.substr(2); $r.uri.length +' '+ $r.uri"),
-      nxt_string("4 БВ") },
-
-    { nxt_string("a = $r.host; a +' '+ a.length +' '+ a"),
-      nxt_string("АБВГДЕЁЖЗИЙ 22 АБВГДЕЁЖЗИЙ") },
-
-    { nxt_string("a = $r.host; a.substr(2, 2)"),
-      nxt_string("Б") },
-
-    { nxt_string("a = $r.header['User-Agent']; a +' '+ a.length +' '+ a"),
-      nxt_string("User-Agent|АБВ 17 User-Agent|АБВ") },
-
-    { nxt_string("var a='';"
-                 "for (p in $r.header) { a += p +':'+ $r.header[p] +',' }"
-                 "a"),
-      nxt_string("01:01|АБВ,02:02|АБВ,03:03|АБВ,") },
-
-    { nxt_string("$r.nonexistent"),
-      nxt_string("undefined") },
-
     { nxt_string("a = 'abcdefgh'; a.substr(3, 15)"),
       nxt_string("defgh") },
 
@@ -2160,7 +2119,59 @@ static njs_unit_test_t  njs_test[] =
                           " valueOf:  function() { return 0 } };   '12'[n]"),
       nxt_string("2") },
 
-    /**/
+    /* Externals. */
+
+    { nxt_string("typeof $r"),
+      nxt_string("undefined") },
+
+    { nxt_string("a = $r.uri; s = a.fromUTF8(); s.length +' '+ s"),
+      nxt_string("3 АБВ") },
+
+    { nxt_string("a = $r.uri; s = a.fromUTF8(2); s.length +' '+ s"),
+      nxt_string("2 БВ") },
+
+    { nxt_string("a = $r.uri; s = a.fromUTF8(2, 4); s.length +' '+ s"),
+      nxt_string("1 Б") },
+
+    { nxt_string("a = $r.uri; a +' '+ a.length +' '+ a"),
+      nxt_string("АБВ 6 АБВ") },
+
+    { nxt_string("$r.uri = 'αβγ'; a = $r.uri; a.length +' '+ a"),
+      nxt_string("6 αβγ") },
+
+    { nxt_string("$r.uri.length +' '+ $r.uri"),
+      nxt_string("6 АБВ") },
+
+    { nxt_string("$r.uri = $r.uri.substr(2); $r.uri.length +' '+ $r.uri"),
+      nxt_string("4 БВ") },
+
+    { nxt_string("a = $r.host; a +' '+ a.length +' '+ a"),
+      nxt_string("АБВГДЕЁЖЗИЙ 22 АБВГДЕЁЖЗИЙ") },
+
+    { nxt_string("a = $r.host; a.substr(2, 2)"),
+      nxt_string("Б") },
+
+    { nxt_string("a = $r.header['User-Agent']; a +' '+ a.length +' '+ a"),
+      nxt_string("User-Agent|АБВ 17 User-Agent|АБВ") },
+
+    { nxt_string("var a='';"
+                 "for (p in $r.header) { a += p +':'+ $r.header[p] +',' }"
+                 "a"),
+      nxt_string("01:01|АБВ,02:02|АБВ,03:03|АБВ,") },
+
+    { nxt_string("$r.external('YES')"),
+      nxt_string("АБВ") },
+
+#if 0
+    { nxt_string("$r.external.call($r, 'YES')"),
+      nxt_string("АБВ") },
+
+    { nxt_string("$r.external.apply($r, ['YES'])"),
+      nxt_string("АБВ") },
+#endif
+
+    { nxt_string("$r.nonexistent"),
+      nxt_string("undefined") },
 
     { nxt_string("'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'.charCodeAt(5)"),
       nxt_string("1077") },
@@ -2248,6 +2259,14 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("'abc ABC aBc'.match(/abc/ig) +''"),
       nxt_string("abc,ABC,aBc") },
 
+    /* Functions. */
+
+    { nxt_string("var a = 1; a()"),
+      nxt_string("TypeError") },
+
+    { nxt_string("var o = {a:1}; o.a()"),
+      nxt_string("TypeError") },
+
     { nxt_string("var q = 1; function x(a, b, c) { q = a } x(5); q"),
       nxt_string("5") },
 
@@ -2269,6 +2288,13 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("function f(a) { return (a > 1) ? a * f(a - 1) : 1 } f(10)"),
       nxt_string("3628800") },
 
+    { nxt_string("var g = function f(a) { return (a > 1) ? a * f(a - 1) : 1 };"
+                 "g(10)"),
+      nxt_string("3628800") },
+
+    { nxt_string("(function f(a) { return (a > 1) ? a * f(a - 1) : 1 })(10)"),
+      nxt_string("3628800") },
+
     /* Recursive fibonacci. */
 
     { nxt_string("function fibo(n) {"
@@ -2317,6 +2343,10 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("function f() { return 5 } f()"),
       nxt_string("5") },
 
+    { nxt_string("function g(x) { return x + 1 }"
+                 "function f(x) { return x } f(g)(2)"),
+      nxt_string("3") },
+
     { nxt_string("function f() { return 5 } f(1)"),
       nxt_string("5") },
 
@@ -2371,6 +2401,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("a = {}; function f(a) { return a + 1 } a.b = f(2); a.b"),
       nxt_string("3") },
 
+    { nxt_string("(function(x) { return x + 1 })(2)"),
+      nxt_string("3") },
+
+    { nxt_string("(function(x) { return x + 1 }(2))"),
+      nxt_string("3") },
+
     { nxt_string("a = (function() { return 1 })(); a"),
       nxt_string("1") },
 
@@ -2392,6 +2428,13 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("a = 0, function(a) { return a + 1 }(2); a"),
       nxt_string("0") },
 
+    { nxt_string("a = (0, function(a) { return a + 1 }(2)); a"),
+      nxt_string("3") },
+
+    { nxt_string("var a = +function f(a) { return a + 1 }(2)"
+                 "var b = f(5); a"),
+      nxt_string("ReferenceError") },
+
     { nxt_string("var o = { f: function(a) { return a * 2 } }; o.f(5)"),
       nxt_string("10") },
 
@@ -3196,6 +3239,33 @@ njs_unit_test_header_each_external(njs_vm_t *vm, njs_value_t *value, void *obj,
 }
 
 
+static njs_ret_t
+njs_unit_test_method_external(njs_vm_t *vm, njs_param_t *param)
+{
+    nxt_int_t          ret;
+    nxt_str_t          s;
+    uintptr_t          next;
+    njs_unit_test_req  *r;
+
+    next = 0;
+
+    if (param->nargs != 0) {
+
+        ret = njs_value_string_copy(vm, &s, njs_argument(param->args, 0),
+                                    &next);
+
+        if (ret == NXT_OK && s.len == 3 && memcmp(s.data, "YES", 3) == 0) {
+            r = njs_value_data(param->object);
+            njs_vm_return_string(vm, r->uri.data, r->uri.len);
+
+            return NXT_OK;
+        }
+    }
+
+    return NXT_ERROR;
+}
+
+
 static njs_ret_t
 njs_unit_test_undefined_external(njs_vm_t *vm, njs_value_t *value, void *obj,
     uintptr_t data)
@@ -3244,6 +3314,18 @@ static njs_external_t  njs_unit_test_r_external[] = {
       NULL,
       0 },
 
+    { nxt_string("external"),
+      NJS_EXTERN_METHOD,
+      NULL,
+      0,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      njs_unit_test_method_external,
+      0 },
+
 };