]> git.kaiwu.me - njs.git/commitdiff
Computed goto support added to vmcode.
authorVadim Zhestikov <v.zhestikov@f5.com>
Tue, 25 Oct 2022 13:43:10 +0000 (06:43 -0700)
committerVadim Zhestikov <v.zhestikov@f5.com>
Tue, 25 Oct 2022 13:43:10 +0000 (06:43 -0700)
auto/clang
auto/computed_goto [new file with mode: 0644]
auto/help
auto/options
auto/summary
configure
src/njs_clang.h
src/njs_disassembler.c
src/njs_parser.c
src/njs_vmcode.c
src/njs_vmcode.h

index 4f4d1fe9dce1b5e4035cdf493353c61df8b5dbdb..270d6e5925baa87ba861d9d7a8e9730300ee583a 100644 (file)
@@ -142,6 +142,25 @@ njs_feature_test="struct __attribute__((packed)) s { char v; };
 . auto/feature
 
 
+njs_feature="GCC __attribute__ fallthrough"
+njs_feature_name=NJS_HAVE_GCC_ATTRIBUTE_FALLTHROUGH
+njs_feature_run=no
+njs_feature_path=
+njs_feature_libs=
+njs_feature_test="int main(int argc, char *argv[]) {
+                    switch (argc) {
+                    case 0:
+                      argc++;
+                      __attribute__((fallthrough));
+                    default:
+                      argc++;
+                    }
+
+                    return argc;
+                  }"
+. auto/feature
+
+
 njs_feature="Address sanitizer"
 njs_feature_name=NJS_HAVE_ADDRESS_SANITIZER
 njs_feature_run=no
diff --git a/auto/computed_goto b/auto/computed_goto
new file mode 100644 (file)
index 0000000..e68fdc5
--- /dev/null
@@ -0,0 +1,25 @@
+
+# Copyright (C) Vadim Zhestikov
+# Copyright (C) NGINX, Inc.
+
+
+NJS_HAVE_COMPUTED_GOTO=NO
+
+
+if [ $NJS_TRY_GOTO = YES ]; then
+
+    njs_feature="Computed goto"
+    njs_feature_name=NJS_HAVE_COMPUTED_GOTO
+    njs_feature_run=no
+    njs_feature_incs=
+    njs_feature_libs=
+    njs_feature_test="int main(void) {
+                        void  *ptr;
+                        ptr = &&label;
+                        goto *ptr;
+                      label:
+                        return 0;
+                      }"
+    . auto/feature
+
+fi
index fcaa354b5c50a41581df3088f0c8f148a5090e50..9e248a1b4de578dd61cc62ada514ee4b6a4dde45 100644 (file)
--- a/auto/help
+++ b/auto/help
@@ -27,6 +27,10 @@ default: "$NJS_LD_OPT"
                             When this option is enabled only PCRE library
                             is discovered.
 
+  --no-goto                 disables computed goto discovery.
+                            When this option is enabled 'switch' statement
+                            will be always used in instead of computed goto.
+
   --no-openssl              disables OpenSSL discovery. When this option is
                             enabled OpenSSL dependant code is not built as a
                             part of libnjs.a.
index 386fd0acb629366131888412e0d4569dee354206..3f6ae6501bc431dea3552c121372b92fe36871bd 100644 (file)
@@ -20,6 +20,8 @@ NJS_OPENSSL=YES
 NJS_PCRE=YES
 NJS_TRY_PCRE2=YES
 
+NJS_TRY_GOTO=YES
+
 NJS_CONFIGURE_OPTIONS=
 
 for njs_option
@@ -50,6 +52,8 @@ do
         --no-pcre)                       NJS_PCRE=NO                         ;;
         --no-pcre2)                      NJS_TRY_PCRE2=NO                    ;;
 
+        --no-goto)                       NJS_TRY_GOTO=NO                     ;;
+
         --help)
             . auto/help
             exit 0
index 8d17807bc108cbce52d410202e994233ac4d3872..46c9deb7d5677cf14f4335fd501ca183d4333799 100644 (file)
@@ -22,6 +22,11 @@ if [ $NJS_HAVE_OPENSSL = YES ]; then
   echo " + using OpenSSL library: $NJS_OPENSSL_LIB"
 fi
 
+if [ $NJS_HAVE_COMPUTED_GOTO = YES ]; then
+  echo " + using computed goto"
+fi
+
+
 echo
 echo " njs build dir: $NJS_BUILD_DIR"
 echo " njs CLI: $NJS_BUILD_DIR/njs"
index 63583d17f0288a34a41dcab53d029ff76b8cb233..8fc71f336a4655ba2fef14af7e661fbc331ce002 100755 (executable)
--- a/configure
+++ b/configure
@@ -46,6 +46,7 @@ NJS_LIB_AUX_LIBS=
 . auto/memalign
 . auto/getrandom
 . auto/stat
+. auto/computed_goto
 . auto/explicit_bzero
 . auto/pcre
 . auto/readline
index a13e13dd2edf13a4a2dbf73fb727b063303f483f..614b509075db0f9d7fcc90263b99095268791ecf 100644 (file)
@@ -146,6 +146,14 @@ njs_leading_zeros64(uint64_t x)
 #endif
 
 
+#if (NJS_HAVE_GCC_ATTRIBUTE_FALLTHROUGH)
+#define NJS_FALLTHROUGH    __attribute__((fallthrough))
+
+#else
+#define NJS_FALLTHROUGH
+#endif
+
+
 #if (NJS_HAVE_GCC_ATTRIBUTE_MALLOC)
 #define NJS_MALLOC_LIKE    __attribute__((__malloc__))
 
index 03a83e8c1fcd1dd8601a2f467041ff4f8aca2694..25d3067936fecbd8c22a074e86beb4e5722d6e1e 100644 (file)
@@ -23,8 +23,6 @@ static njs_code_name_t  code_names[] = {
           njs_str("OBJECT          ") },
     { NJS_VMCODE_FUNCTION, sizeof(njs_vmcode_function_t),
           njs_str("FUNCTION        ") },
-    { NJS_VMCODE_THIS, sizeof(njs_vmcode_this_t),
-          njs_str("THIS            ") },
     { NJS_VMCODE_ARGUMENTS, sizeof(njs_vmcode_arguments_t),
           njs_str("ARGUMENTS       ") },
     { NJS_VMCODE_REGEXP, sizeof(njs_vmcode_regexp_t),
index 2b94d3d4cf81770baf8fad11a45a03052685ba2b..66d7c7c89b9101121ebc62cba6d9437dba8f69fc 100644 (file)
@@ -4527,7 +4527,7 @@ njs_parser_expression_comma(njs_parser_t *parser, njs_lexer_token_t *token,
     njs_parser_next(parser, njs_parser_assignment_expression);
 
     return njs_parser_expression_node(parser, token, current, NJS_TOKEN_COMMA,
-                                       NJS_VMCODE_NOP,
+                                       0,
                                        njs_parser_expression_comma);
 }
 
index cab230f5fe74447fe09f6ff77cdb89db1eb4ef00..033177f450891212bebc31e1f75cb5fafdae4a3c 100644 (file)
@@ -108,7 +108,6 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_char *pc, void *promise_cap,
     njs_vmcode_variable_t        *var;
     njs_vmcode_prop_get_t        *get;
     njs_vmcode_prop_set_t        *set;
-    njs_vmcode_operation_t       op;
     njs_vmcode_prop_next_t       *pnext;
     njs_vmcode_test_jump_t       *test_jump;
     njs_vmcode_equal_jump_t      *equal;
@@ -121,980 +120,1694 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_char *pc, void *promise_cap,
 
     njs_vmcode_debug(vm, pc, "ENTER");
 
-next:
+#if !defined(NJS_HAVE_COMPUTED_GOTO)
+    #define SWITCH(op)      switch (op)
+    #define CASE(op)        case op
+    #define BREAK           pc += ret; NEXT
+
+    #define NEXT            vmcode = (njs_vmcode_generic_t *) pc;             \
+                            goto next
+
+    #define NEXT_LBL        next:
+    #define FALLTHROUGH     NJS_FALLTHROUGH
+
+#else
+    #define SWITCH(op)      goto *switch_tbl[(uint8_t) op];
+    #define CASE(op)        case_ ## op
+    #define BREAK           pc += ret; NEXT
+
+    #define NEXT            vmcode = (njs_vmcode_generic_t *) pc;             \
+                            SWITCH (vmcode->code.operation)
+
+    #define NEXT_LBL
+    #define FALLTHROUGH
+
+    #define NJS_GOTO_ROW(name)   [ (uint8_t) name ] = &&case_ ## name
+
+    static const void * const switch_tbl[NJS_VMCODES] = {
+
+        NJS_GOTO_ROW(NJS_VMCODE_PUT_ARG),
+        NJS_GOTO_ROW(NJS_VMCODE_STOP),
+        NJS_GOTO_ROW(NJS_VMCODE_JUMP),
+        NJS_GOTO_ROW(NJS_VMCODE_PROPERTY_SET),
+        NJS_GOTO_ROW(NJS_VMCODE_PROPERTY_ACCESSOR),
+        NJS_GOTO_ROW(NJS_VMCODE_IF_TRUE_JUMP),
+        NJS_GOTO_ROW(NJS_VMCODE_IF_FALSE_JUMP),
+        NJS_GOTO_ROW(NJS_VMCODE_IF_EQUAL_JUMP),
+        NJS_GOTO_ROW(NJS_VMCODE_PROPERTY_INIT),
+        NJS_GOTO_ROW(NJS_VMCODE_RETURN),
+        NJS_GOTO_ROW(NJS_VMCODE_FUNCTION_COPY),
+        NJS_GOTO_ROW(NJS_VMCODE_FUNCTION_FRAME),
+        NJS_GOTO_ROW(NJS_VMCODE_METHOD_FRAME),
+        NJS_GOTO_ROW(NJS_VMCODE_FUNCTION_CALL),
+        NJS_GOTO_ROW(NJS_VMCODE_PROPERTY_NEXT),
+        NJS_GOTO_ROW(NJS_VMCODE_ARGUMENTS),
+        NJS_GOTO_ROW(NJS_VMCODE_PROTO_INIT),
+        NJS_GOTO_ROW(NJS_VMCODE_TO_PROPERTY_KEY),
+        NJS_GOTO_ROW(NJS_VMCODE_TO_PROPERTY_KEY_CHK),
+        NJS_GOTO_ROW(NJS_VMCODE_SET_FUNCTION_NAME),
+        NJS_GOTO_ROW(NJS_VMCODE_IMPORT),
+        NJS_GOTO_ROW(NJS_VMCODE_AWAIT),
+        NJS_GOTO_ROW(NJS_VMCODE_TRY_START),
+        NJS_GOTO_ROW(NJS_VMCODE_THROW),
+        NJS_GOTO_ROW(NJS_VMCODE_TRY_BREAK),
+        NJS_GOTO_ROW(NJS_VMCODE_TRY_CONTINUE),
+        NJS_GOTO_ROW(NJS_VMCODE_TRY_END),
+        NJS_GOTO_ROW(NJS_VMCODE_CATCH),
+        NJS_GOTO_ROW(NJS_VMCODE_FINALLY),
+        NJS_GOTO_ROW(NJS_VMCODE_LET),
+        NJS_GOTO_ROW(NJS_VMCODE_LET_UPDATE),
+        NJS_GOTO_ROW(NJS_VMCODE_INITIALIZATION_TEST),
+        NJS_GOTO_ROW(NJS_VMCODE_NOT_INITIALIZED),
+        NJS_GOTO_ROW(NJS_VMCODE_ASSIGNMENT_ERROR),
+        NJS_GOTO_ROW(NJS_VMCODE_ERROR),
+        NJS_GOTO_ROW(NJS_VMCODE_MOVE),
+        NJS_GOTO_ROW(NJS_VMCODE_PROPERTY_GET),
+        NJS_GOTO_ROW(NJS_VMCODE_INCREMENT),
+        NJS_GOTO_ROW(NJS_VMCODE_POST_INCREMENT),
+        NJS_GOTO_ROW(NJS_VMCODE_DECREMENT),
+        NJS_GOTO_ROW(NJS_VMCODE_POST_DECREMENT),
+        NJS_GOTO_ROW(NJS_VMCODE_TRY_RETURN),
+        NJS_GOTO_ROW(NJS_VMCODE_GLOBAL_GET),
+        NJS_GOTO_ROW(NJS_VMCODE_LESS),
+        NJS_GOTO_ROW(NJS_VMCODE_GREATER),
+        NJS_GOTO_ROW(NJS_VMCODE_LESS_OR_EQUAL),
+        NJS_GOTO_ROW(NJS_VMCODE_GREATER_OR_EQUAL),
+        NJS_GOTO_ROW(NJS_VMCODE_ADDITION),
+        NJS_GOTO_ROW(NJS_VMCODE_EQUAL),
+        NJS_GOTO_ROW(NJS_VMCODE_NOT_EQUAL),
+        NJS_GOTO_ROW(NJS_VMCODE_SUBSTRACTION),
+        NJS_GOTO_ROW(NJS_VMCODE_MULTIPLICATION),
+        NJS_GOTO_ROW(NJS_VMCODE_EXPONENTIATION),
+        NJS_GOTO_ROW(NJS_VMCODE_DIVISION),
+        NJS_GOTO_ROW(NJS_VMCODE_REMAINDER),
+        NJS_GOTO_ROW(NJS_VMCODE_BITWISE_AND),
+        NJS_GOTO_ROW(NJS_VMCODE_BITWISE_OR),
+        NJS_GOTO_ROW(NJS_VMCODE_BITWISE_XOR),
+        NJS_GOTO_ROW(NJS_VMCODE_LEFT_SHIFT),
+        NJS_GOTO_ROW(NJS_VMCODE_RIGHT_SHIFT),
+        NJS_GOTO_ROW(NJS_VMCODE_UNSIGNED_RIGHT_SHIFT),
+        NJS_GOTO_ROW(NJS_VMCODE_OBJECT_COPY),
+        NJS_GOTO_ROW(NJS_VMCODE_TEMPLATE_LITERAL),
+        NJS_GOTO_ROW(NJS_VMCODE_PROPERTY_IN),
+        NJS_GOTO_ROW(NJS_VMCODE_PROPERTY_DELETE),
+        NJS_GOTO_ROW(NJS_VMCODE_PROPERTY_FOREACH),
+        NJS_GOTO_ROW(NJS_VMCODE_STRICT_EQUAL),
+        NJS_GOTO_ROW(NJS_VMCODE_STRICT_NOT_EQUAL),
+        NJS_GOTO_ROW(NJS_VMCODE_TEST_IF_TRUE),
+        NJS_GOTO_ROW(NJS_VMCODE_TEST_IF_FALSE),
+        NJS_GOTO_ROW(NJS_VMCODE_COALESCE),
+        NJS_GOTO_ROW(NJS_VMCODE_UNARY_PLUS),
+        NJS_GOTO_ROW(NJS_VMCODE_UNARY_NEGATION),
+        NJS_GOTO_ROW(NJS_VMCODE_BITWISE_NOT),
+        NJS_GOTO_ROW(NJS_VMCODE_LOGICAL_NOT),
+        NJS_GOTO_ROW(NJS_VMCODE_OBJECT),
+        NJS_GOTO_ROW(NJS_VMCODE_ARRAY),
+        NJS_GOTO_ROW(NJS_VMCODE_FUNCTION),
+        NJS_GOTO_ROW(NJS_VMCODE_REGEXP),
+        NJS_GOTO_ROW(NJS_VMCODE_INSTANCE_OF),
+        NJS_GOTO_ROW(NJS_VMCODE_TYPEOF),
+        NJS_GOTO_ROW(NJS_VMCODE_VOID),
+        NJS_GOTO_ROW(NJS_VMCODE_DELETE),
+        NJS_GOTO_ROW(NJS_VMCODE_DEBUGGER),
+    };
+
+#endif
+
+    vmcode = (njs_vmcode_generic_t *) pc;
+
+NEXT_LBL;
+
+    SWITCH (vmcode->code.operation) {
+
+    CASE (NJS_VMCODE_MOVE):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        *retval = *value1;
+
+        pc += sizeof(njs_vmcode_move_t);
+        NEXT;
+
+    CASE (NJS_VMCODE_PROPERTY_GET):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        get = (njs_vmcode_prop_get_t *) pc;
+        njs_vmcode_operand(vm, get->value, retval);
+
+        if (njs_slow_path(!njs_is_index_or_key(value2))) {
+            if (njs_slow_path(njs_is_null_or_undefined(value1))) {
+                (void) njs_throw_cannot_property(vm, value1, value2, "get");
+                goto error;
+            }
+
+            ret = njs_value_to_key(vm, &primitive1, value2);
+            if (njs_slow_path(ret != NJS_OK)) {
+                goto error;
+            }
+
+            value2 = &primitive1;
+        }
+
+        ret = njs_value_property(vm, value1, value2, retval);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
+
+        pc += sizeof(njs_vmcode_prop_get_t);
+        NEXT;
+
+    CASE (NJS_VMCODE_INCREMENT):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        if (njs_slow_path(!njs_is_numeric(value2))) {
+            ret = njs_value_to_numeric(vm, value2, &numeric1);
+            if (njs_slow_path(ret != NJS_OK)) {
+                goto error;
+            }
+
+            num = njs_number(&numeric1);
+
+        } else {
+            num = njs_number(value2);
+        }
+
+        njs_set_number(value1, num + 1);
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+
+        *retval = *value1;
+
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
+
+    CASE (NJS_VMCODE_POST_INCREMENT):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        if (njs_slow_path(!njs_is_numeric(value2))) {
+            ret = njs_value_to_numeric(vm, value2, &numeric1);
+            if (njs_slow_path(ret != NJS_OK)) {
+                goto error;
+            }
+
+            num = njs_number(&numeric1);
+
+        } else {
+            num = njs_number(value2);
+        }
+
+        njs_set_number(value1, num + 1);
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+
+        njs_set_number(retval, num);
+
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
+
+    CASE (NJS_VMCODE_DECREMENT):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        if (njs_slow_path(!njs_is_numeric(value2))) {
+            ret = njs_value_to_numeric(vm, value2, &numeric1);
+            if (njs_slow_path(ret != NJS_OK)) {
+                goto error;
+            }
+
+            num = njs_number(&numeric1);
+
+        } else {
+            num = njs_number(value2);
+        }
+
+        njs_set_number(value1, num - 1);
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+
+        *retval = *value1;
+
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
+
+    CASE (NJS_VMCODE_POST_DECREMENT):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        if (njs_slow_path(!njs_is_numeric(value2))) {
+            ret = njs_value_to_numeric(vm, value2, &numeric1);
+            if (njs_slow_path(ret != NJS_OK)) {
+                goto error;
+            }
+
+            num = njs_number(&numeric1);
+
+        } else {
+            num = njs_number(value2);
+        }
+
+        njs_set_number(value1, num - 1);
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+
+        njs_set_number(retval, num);
+
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
+
+    CASE (NJS_VMCODE_GLOBAL_GET):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        get = (njs_vmcode_prop_get_t *) pc;
+        njs_vmcode_operand(vm, get->value, retval);
+
+        ret = njs_value_property(vm, value1, value2, retval);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
+
+        pc += sizeof(njs_vmcode_prop_get_t);
+
+        if (ret == NJS_OK) {
+            pc += sizeof(njs_vmcode_error_t);
+        }
+
+        NEXT;
+
+    /*
+     * njs_vmcode_try_return() saves a return value to use it later by
+     * njs_vmcode_finally(), and jumps to the nearest try_break block.
+     */
+    CASE (NJS_VMCODE_TRY_RETURN):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        *retval = *value1;
+
+        try_return = (njs_vmcode_try_return_t *) pc;
+        pc += try_return->offset;
+        NEXT;
+
+    CASE (NJS_VMCODE_LESS):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        if (njs_slow_path(!njs_is_primitive(value1))) {
+            ret = njs_value_to_primitive(vm, &primitive1, value1, 0);
+            if (ret != NJS_OK) {
+                goto error;
+            }
+
+            value1 = &primitive1;
+        }
+
+        if (njs_slow_path(!njs_is_primitive(value2))) {
+            ret = njs_value_to_primitive(vm, &primitive2, value2, 0);
+            if (ret != NJS_OK) {
+                goto error;
+            }
+
+            value2 = &primitive2;
+        }
+
+        if (njs_slow_path(njs_is_symbol(value1)
+                          || njs_is_symbol(value2)))
+        {
+            njs_symbol_conversion_failed(vm, 0);
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+
+        njs_set_boolean(retval,
+                        njs_primitive_values_compare(vm, value1, value2) > 0);
+
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
+
+    CASE (NJS_VMCODE_GREATER):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        if (njs_slow_path(!njs_is_primitive(value1))) {
+            ret = njs_value_to_primitive(vm, &primitive1, value1, 0);
+            if (ret != NJS_OK) {
+                goto error;
+            }
+
+            value1 = &primitive1;
+        }
+
+        if (njs_slow_path(!njs_is_primitive(value2))) {
+            ret = njs_value_to_primitive(vm, &primitive2, value2, 0);
+            if (ret != NJS_OK) {
+                goto error;
+            }
+
+            value2 = &primitive2;
+        }
+
+        if (njs_slow_path(njs_is_symbol(value1)
+                          || njs_is_symbol(value2)))
+        {
+            njs_symbol_conversion_failed(vm, 0);
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+
+        njs_set_boolean(retval,
+                        njs_primitive_values_compare(vm, value2, value1) > 0);
+
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
+
+    CASE (NJS_VMCODE_LESS_OR_EQUAL):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        if (njs_slow_path(!njs_is_primitive(value1))) {
+            ret = njs_value_to_primitive(vm, &primitive1, value1, 0);
+            if (ret != NJS_OK) {
+                goto error;
+            }
+
+            value1 = &primitive1;
+        }
+
+        if (njs_slow_path(!njs_is_primitive(value2))) {
+            ret = njs_value_to_primitive(vm, &primitive2, value2, 0);
+            if (ret != NJS_OK) {
+                goto error;
+            }
+
+            value2 = &primitive2;
+        }
+
+        if (njs_slow_path(njs_is_symbol(value1)
+                          || njs_is_symbol(value2)))
+        {
+            njs_symbol_conversion_failed(vm, 0);
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+
+        njs_set_boolean(retval,
+                        njs_primitive_values_compare(vm, value2, value1) == 0);
+
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
+
+    CASE (NJS_VMCODE_GREATER_OR_EQUAL):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        if (njs_slow_path(!njs_is_primitive(value1))) {
+            ret = njs_value_to_primitive(vm, &primitive1, value1, 0);
+            if (ret != NJS_OK) {
+                goto error;
+            }
+
+            value1 = &primitive1;
+        }
+
+        if (njs_slow_path(!njs_is_primitive(value2))) {
+            ret = njs_value_to_primitive(vm, &primitive2, value2, 0);
+            if (ret != NJS_OK) {
+                goto error;
+            }
+
+            value2 = &primitive2;
+        }
+
+        if (njs_slow_path(njs_is_symbol(value1)
+                          || njs_is_symbol(value2)))
+        {
+            njs_symbol_conversion_failed(vm, 0);
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+
+        njs_set_boolean(retval,
+                        njs_primitive_values_compare(vm, value1, value2) == 0);
+
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
+
+    CASE (NJS_VMCODE_ADDITION):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        if (njs_slow_path(!njs_is_primitive(value1))) {
+            hint = njs_is_date(value1);
+            ret = njs_value_to_primitive(vm, &primitive1, value1, hint);
+            if (ret != NJS_OK) {
+                goto error;
+            }
+
+            value1 = &primitive1;
+        }
+
+        if (njs_slow_path(!njs_is_primitive(value2))) {
+            hint =  njs_is_date(value2);
+            ret = njs_value_to_primitive(vm, &primitive2, value2, hint);
+            if (ret != NJS_OK) {
+                goto error;
+            }
+
+            value2 = &primitive2;
+        }
+
+        if (njs_slow_path(njs_is_symbol(value1)
+                          || njs_is_symbol(value2)))
+        {
+            njs_symbol_conversion_failed(vm,
+                (njs_is_string(value1) || njs_is_string(value2)));
+
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+
+        if (njs_fast_path(njs_is_numeric(value1)
+                          && njs_is_numeric(value2)))
+        {
+            njs_set_number(retval, njs_number(value1)
+                                   + njs_number(value2));
+            pc += sizeof(njs_vmcode_3addr_t);
+            NEXT;
+        }
+
+        if (njs_is_string(value1)) {
+            s1 = value1;
+            s2 = &dst;
+            src = value2;
+
+        } else {
+            s1 = &dst;
+            s2 = value2;
+            src = value1;
+        }
+
+        ret = njs_primitive_value_to_string(vm, &dst, src);
+        if (njs_slow_path(ret != NJS_OK)) {
+            goto error;
+        }
+
+        ret = njs_string_concat(vm, s1, s2);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
+
+        *retval = vm->retval;
+
+        BREAK;
+
+    CASE (NJS_VMCODE_EQUAL):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        ret = njs_values_equal(vm, value1, value2);
+        if (njs_slow_path(ret < 0)) {
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_set_boolean(retval, ret);
+
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
+
+    CASE (NJS_VMCODE_NOT_EQUAL):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        ret = njs_values_equal(vm, value1, value2);
+        if (njs_slow_path(ret < 0)) {
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_set_boolean(retval, !ret);
+
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
+
+#define NJS_PRE_NUMERIC                                                       \
+                                                                              \
+        if (njs_slow_path(!njs_is_numeric(value1))) {                         \
+            ret = njs_value_to_numeric(vm, value1, &numeric1);                \
+            if (njs_slow_path(ret != NJS_OK)) {                               \
+                goto error;                                                   \
+            }                                                                 \
+                                                                              \
+            value1 = &numeric1;                                               \
+        }                                                                     \
+                                                                              \
+        if (njs_slow_path(!njs_is_numeric(value2))) {                         \
+            ret = njs_value_to_numeric(vm, value2, &numeric2);                \
+            if (njs_slow_path(ret != NJS_OK)) {                               \
+                goto error;                                                   \
+            }                                                                 \
+                                                                              \
+            value2 = &numeric2;                                               \
+        }                                                                     \
+                                                                              \
+        num = njs_number(value1);                                             \
+                                                                              \
+        njs_vmcode_operand(vm, vmcode->operand1, retval);                     \
+        pc += sizeof(njs_vmcode_3addr_t)
+
+    CASE (NJS_VMCODE_SUBSTRACTION):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        NJS_PRE_NUMERIC;
+
+        num -= njs_number(value2);
+
+        njs_set_number(retval, num);
+        NEXT;
+
+    CASE (NJS_VMCODE_MULTIPLICATION):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        NJS_PRE_NUMERIC;
+
+        num *= njs_number(value2);
+
+        njs_set_number(retval, num);
+        NEXT;
+
+    CASE (NJS_VMCODE_EXPONENTIATION):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        NJS_PRE_NUMERIC;
+
+        exponent = njs_number(value2);
+        /*
+         * According to ES7:
+         *  1. If exponent is NaN, the result should be NaN;
+         *  2. The result of +/-1 ** +/-Infinity should be NaN.
+         */
+        valid = njs_expect(1, fabs(num) != 1
+                              || (!isnan(exponent)
+                                  && !isinf(exponent)));
+
+        num = valid ? pow(num, exponent) : NAN;
+
+        njs_set_number(retval, num);
+        NEXT;
+
+    CASE (NJS_VMCODE_DIVISION):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        NJS_PRE_NUMERIC;
+
+        num /= njs_number(value2);
+
+        njs_set_number(retval, num);
+        NEXT;
+
+    CASE (NJS_VMCODE_REMAINDER):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        NJS_PRE_NUMERIC;
+
+        num = fmod(num, njs_number(value2));
+
+        njs_set_number(retval, num);
+        NEXT;
+
+    CASE (NJS_VMCODE_BITWISE_AND):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        NJS_PRE_NUMERIC;
+
+        i32 = njs_number_to_int32(njs_number(value2));
+        i32 &= njs_number_to_int32(num);
+
+        njs_set_int32(retval, i32);
+        NEXT;
+
+    CASE (NJS_VMCODE_BITWISE_OR):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        NJS_PRE_NUMERIC;
+
+        i32 = njs_number_to_int32(njs_number(value2));
+        i32 |= njs_number_to_int32(num);
+
+        njs_set_int32(retval, i32);
+        NEXT;
+
+    CASE (NJS_VMCODE_BITWISE_XOR):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        NJS_PRE_NUMERIC;
+
+        i32 = njs_number_to_int32(njs_number(value2));
+        i32 ^= njs_number_to_int32(num);
+
+        njs_set_int32(retval, i32);
+        NEXT;
+
+    CASE (NJS_VMCODE_LEFT_SHIFT):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        NJS_PRE_NUMERIC;
+
+        u32 = njs_number_to_uint32(njs_number(value2)) & 0x1f;
+        i32 = njs_number_to_int32(num);
+
+        /* Shifting of negative numbers is undefined. */
+        i32 = (uint32_t) i32 << u32;
+
+        njs_set_int32(retval, i32);
+        NEXT;
+
+    CASE (NJS_VMCODE_RIGHT_SHIFT):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        NJS_PRE_NUMERIC;
 
-    for ( ;; ) {
+        u32 = njs_number_to_uint32(njs_number(value2)) & 0x1f;
+        i32 = njs_number_to_int32(num);
 
-        vmcode = (njs_vmcode_generic_t *) pc;
+        i32 >>= u32;
+
+        njs_set_int32(retval, i32);
+        NEXT;
+
+    CASE (NJS_VMCODE_UNSIGNED_RIGHT_SHIFT):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        NJS_PRE_NUMERIC;
+
+        u32 = njs_number_to_uint32(njs_number(value2)) & 0x1f;
+        njs_set_uint32(retval, njs_number_to_uint32(num) >> u32);
+        NEXT;
+
+    CASE (NJS_VMCODE_OBJECT_COPY):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        ret = njs_vmcode_object_copy(vm, value1, NULL);
+
+        if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
+
+        BREAK;
+
+    CASE (NJS_VMCODE_TEMPLATE_LITERAL):
+        njs_vmcode_debug_opcode();
 
-        /*
-         * The first operand is passed as is in value2 to
-         *   NJS_VMCODE_JUMP,
-         *   NJS_VMCODE_IF_TRUE_JUMP,
-         *   NJS_VMCODE_IF_FALSE_JUMP,
-         *   NJS_VMCODE_FUNCTION_FRAME,
-         *   NJS_VMCODE_FUNCTION_CALL,
-         *   NJS_VMCODE_RETURN,
-         *   NJS_VMCODE_TRY_START,
-         *   NJS_VMCODE_TRY_CONTINUE,
-         *   NJS_VMCODE_TRY_BREAK,
-         *   NJS_VMCODE_TRY_END,
-         *   NJS_VMCODE_CATCH,
-         *   NJS_VMCODE_THROW,
-         *   NJS_VMCODE_STOP.
-         */
         value2 = (njs_value_t *) vmcode->operand1;
-        value1 = NULL;
 
-        switch (vmcode->code.operands) {
+        ret = njs_vmcode_template_literal(vm, NULL, value2);
 
-        case NJS_VMCODE_3OPERANDS:
-            njs_vmcode_operand(vm, vmcode->operand3, value2);
+        if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
+
+        BREAK;
+
+    CASE (NJS_VMCODE_PROPERTY_IN):
+        njs_vmcode_debug_opcode();
 
-            /* Fall through. */
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-        case NJS_VMCODE_2OPERANDS:
-            njs_vmcode_operand(vm, vmcode->operand2, value1);
+        ret = njs_vmcode_property_in(vm, value1, value2);
+
+        if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+            goto error;
         }
 
-        op = vmcode->code.operation;
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
 
-        /*
-         * On success an operation returns size of the bytecode,
-         * a jump offset or zero after the call or return operations.
-         * Jumps can return a negative offset.  Compilers can generate
-         *    (ret < 0 && ret >= NJS_PREEMPT)
-         * as a single unsigned comparision.
-         */
+        BREAK;
+
+    CASE (NJS_VMCODE_PROPERTY_DELETE):
+        njs_vmcode_debug_opcode();
 
-#ifdef NJS_DEBUG_OPCODE
-        if (vm->options.opcode_debug) {
-            njs_disassemble(pc, NULL, 1, NULL);
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        ret = njs_value_property_delete(vm, value1, value2, NULL, 1);
+        if (njs_fast_path(ret != NJS_ERROR)) {
+            vm->retval = njs_value_true;
+
+            ret = sizeof(njs_vmcode_3addr_t);
         }
-#endif
 
-        if (op > NJS_VMCODE_NORET) {
+        if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+            goto error;
+        }
 
-            if (op == NJS_VMCODE_MOVE) {
-                njs_vmcode_operand(vm, vmcode->operand1, retval);
-                *retval = *value1;
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
 
-                pc += sizeof(njs_vmcode_move_t);
-                goto next;
-            }
+        BREAK;
 
-            if (op == NJS_VMCODE_PROPERTY_GET) {
-                get = (njs_vmcode_prop_get_t *) pc;
-                njs_vmcode_operand(vm, get->value, retval);
+    CASE (NJS_VMCODE_PROPERTY_FOREACH):
+        njs_vmcode_debug_opcode();
 
-                if (njs_slow_path(!njs_is_index_or_key(value2))) {
-                    if (njs_slow_path(njs_is_null_or_undefined(value1))) {
-                        (void) njs_throw_cannot_property(vm, value1, value2,
-                                                         "get");
-                        goto error;
-                    }
+        value2 = (njs_value_t *) vmcode->operand1;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                    ret = njs_value_to_key(vm, &primitive1, value2);
-                    if (njs_slow_path(ret != NJS_OK)) {
-                        goto error;
-                    }
+        ret = njs_vmcode_property_foreach(vm, value1, value2, pc);
 
-                    value2 = &primitive1;
-                }
+        if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+            goto error;
+        }
 
-                ret = njs_value_property(vm, value1, value2, retval);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
 
-                pc += sizeof(njs_vmcode_prop_get_t);
-                goto next;
-            }
+        BREAK;
 
-            switch (op) {
-            case NJS_VMCODE_INCREMENT:
-            case NJS_VMCODE_POST_INCREMENT:
-            case NJS_VMCODE_DECREMENT:
-            case NJS_VMCODE_POST_DECREMENT:
-                if (njs_slow_path(!njs_is_numeric(value2))) {
-                    ret = njs_value_to_numeric(vm, value2, &numeric1);
-                    if (njs_slow_path(ret != NJS_OK)) {
-                        goto error;
-                    }
-
-                    num = njs_number(&numeric1);
-
-                } else {
-                    num = njs_number(value2);
-                }
+    CASE (NJS_VMCODE_STRICT_EQUAL):
+        njs_vmcode_debug_opcode();
 
-                njs_set_number(value1,
-                           num + (1 - 2 * ((op - NJS_VMCODE_INCREMENT) >> 1)));
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                njs_vmcode_operand(vm, vmcode->operand1, retval);
+        ret = njs_values_strict_equal(value1, value2);
 
-                if (op & 1) {
-                    njs_set_number(retval, num);
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_set_boolean(retval, ret);
 
-                } else {
-                    *retval = *value1;
-                }
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
 
-                pc += sizeof(njs_vmcode_3addr_t);
-                goto next;
+    CASE (NJS_VMCODE_STRICT_NOT_EQUAL):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_GLOBAL_GET:
-                get = (njs_vmcode_prop_get_t *) pc;
-                njs_vmcode_operand(vm, get->value, retval);
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                ret = njs_value_property(vm, value1, value2, retval);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+        ret = njs_values_strict_equal(value1, value2);
 
-                pc += sizeof(njs_vmcode_prop_get_t);
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_set_boolean(retval, !ret);
 
-                if (ret == NJS_OK) {
-                    pc += sizeof(njs_vmcode_error_t);
-                }
+        pc += sizeof(njs_vmcode_3addr_t);
+        NEXT;
 
-                goto next;
-
-            /*
-             * njs_vmcode_try_return() saves a return value to use it later by
-             * njs_vmcode_finally(), and jumps to the nearest try_break block.
-             */
-            case NJS_VMCODE_TRY_RETURN:
-                njs_vmcode_operand(vm, vmcode->operand1, retval);
-                *retval = *value1;
-
-                try_return = (njs_vmcode_try_return_t *) pc;
-                pc += try_return->offset;
-                goto next;
-
-            case NJS_VMCODE_LESS:
-            case NJS_VMCODE_GREATER:
-            case NJS_VMCODE_LESS_OR_EQUAL:
-            case NJS_VMCODE_GREATER_OR_EQUAL:
-            case NJS_VMCODE_ADDITION:
-                if (njs_slow_path(!njs_is_primitive(value1))) {
-                    hint = (op == NJS_VMCODE_ADDITION) && njs_is_date(value1);
-                    ret = njs_value_to_primitive(vm, &primitive1, value1, hint);
-                    if (ret != NJS_OK) {
-                        goto error;
-                    }
-
-                    value1 = &primitive1;
-                }
+    CASE (NJS_VMCODE_TEST_IF_TRUE):
+        njs_vmcode_debug_opcode();
 
-                if (njs_slow_path(!njs_is_primitive(value2))) {
-                    hint = (op == NJS_VMCODE_ADDITION) && njs_is_date(value2);
-                    ret = njs_value_to_primitive(vm, &primitive2, value2, hint);
-                    if (ret != NJS_OK) {
-                        goto error;
-                    }
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                    value2 = &primitive2;
-                }
+        ret = njs_is_true(value1);
 
-                if (njs_slow_path(njs_is_symbol(value1)
-                                  || njs_is_symbol(value2)))
-                {
-                    njs_symbol_conversion_failed(vm,
-                        (op == NJS_VMCODE_ADDITION) &&
-                        (njs_is_string(value1) || njs_is_string(value2)));
+        if (ret) {
+            test_jump = (njs_vmcode_test_jump_t *) pc;
+            ret = test_jump->offset;
 
-                    goto error;
-                }
+        } else {
+            ret = sizeof(njs_vmcode_3addr_t);
+        }
 
-                njs_vmcode_operand(vm, vmcode->operand1, retval);
-
-                if (op == NJS_VMCODE_ADDITION) {
-                    if (njs_fast_path(njs_is_numeric(value1)
-                                      && njs_is_numeric(value2)))
-                    {
-                        njs_set_number(retval, njs_number(value1)
-                                               + njs_number(value2));
-                        pc += sizeof(njs_vmcode_3addr_t);
-                        goto next;
-                    }
-
-                    if (njs_is_string(value1)) {
-                        s1 = value1;
-                        s2 = &dst;
-                        src = value2;
-
-                    } else {
-                        s1 = &dst;
-                        s2 = value2;
-                        src = value1;
-                    }
-
-                    ret = njs_primitive_value_to_string(vm, &dst, src);
-                    if (njs_slow_path(ret != NJS_OK)) {
-                        goto error;
-                    }
-
-                    ret = njs_string_concat(vm, s1, s2);
-                    if (njs_slow_path(ret == NJS_ERROR)) {
-                        goto error;
-                    }
-
-                    *retval = vm->retval;
-
-                    pc += ret;
-                    goto next;
-                }
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        *retval = *value1;
 
-                if ((uint8_t) (op - NJS_VMCODE_GREATER) < 2) {
-                    /* NJS_VMCODE_GREATER, NJS_VMCODE_LESS_OR_EQUAL */
-                    src = value1;
-                    value1 = value2;
-                    value2 = src;
-                }
+        BREAK;
 
-                ret = njs_primitive_values_compare(vm, value1, value2);
+    CASE (NJS_VMCODE_TEST_IF_FALSE):
+        njs_vmcode_debug_opcode();
 
-                if (op < NJS_VMCODE_LESS_OR_EQUAL) {
-                    ret = ret > 0;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                } else {
-                    ret = ret == 0;
-                }
+        ret = !njs_is_true(value1);
 
-                njs_set_boolean(retval, ret);
+        if (ret) {
+            test_jump = (njs_vmcode_test_jump_t *) pc;
+            ret = test_jump->offset;
 
-                pc += sizeof(njs_vmcode_3addr_t);
-                goto next;
+        } else {
+            ret = sizeof(njs_vmcode_3addr_t);
+        }
 
-            case NJS_VMCODE_EQUAL:
-            case NJS_VMCODE_NOT_EQUAL:
-                ret = njs_values_equal(vm, value1, value2);
-                if (njs_slow_path(ret < 0)) {
-                    goto error;
-                }
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        *retval = *value1;
 
-                ret ^= op - NJS_VMCODE_EQUAL;
-
-                njs_vmcode_operand(vm, vmcode->operand1, retval);
-                njs_set_boolean(retval, ret);
-
-                pc += sizeof(njs_vmcode_3addr_t);
-                goto next;
-
-            case NJS_VMCODE_SUBSTRACTION:
-            case NJS_VMCODE_MULTIPLICATION:
-            case NJS_VMCODE_EXPONENTIATION:
-            case NJS_VMCODE_DIVISION:
-            case NJS_VMCODE_REMAINDER:
-            case NJS_VMCODE_BITWISE_AND:
-            case NJS_VMCODE_BITWISE_OR:
-            case NJS_VMCODE_BITWISE_XOR:
-            case NJS_VMCODE_LEFT_SHIFT:
-            case NJS_VMCODE_RIGHT_SHIFT:
-            case NJS_VMCODE_UNSIGNED_RIGHT_SHIFT:
-                if (njs_slow_path(!njs_is_numeric(value1))) {
-                    ret = njs_value_to_numeric(vm, value1, &numeric1);
-                    if (njs_slow_path(ret != NJS_OK)) {
-                        goto error;
-                    }
-
-                    value1 = &numeric1;
-                }
+        BREAK;
 
-                if (njs_slow_path(!njs_is_numeric(value2))) {
-                    ret = njs_value_to_numeric(vm, value2, &numeric2);
-                    if (njs_slow_path(ret != NJS_OK)) {
-                        goto error;
-                    }
+    CASE (NJS_VMCODE_COALESCE):
+        njs_vmcode_debug_opcode();
 
-                    value2 = &numeric2;
-                }
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                num = njs_number(value1);
+        ret = !njs_is_null_or_undefined(value1);
 
-                njs_vmcode_operand(vm, vmcode->operand1, retval);
-                pc += sizeof(njs_vmcode_3addr_t);
+        if (ret) {
+            test_jump = (njs_vmcode_test_jump_t *) pc;
+            ret = test_jump->offset;
 
-                switch (op) {
-                case NJS_VMCODE_SUBSTRACTION:
-                    num -= njs_number(value2);
-                    break;
+        } else {
+            ret = sizeof(njs_vmcode_3addr_t);
+        }
 
-                case NJS_VMCODE_MULTIPLICATION:
-                    num *= njs_number(value2);
-                    break;
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        *retval = *value1;
 
-                case NJS_VMCODE_EXPONENTIATION:
-                    exponent = njs_number(value2);
+        BREAK;
 
-                    /*
-                     * According to ES7:
-                     *  1. If exponent is NaN, the result should be NaN;
-                     *  2. The result of +/-1 ** +/-Infinity should be NaN.
-                     */
-                    valid = njs_expect(1, fabs(num) != 1
-                                          || (!isnan(exponent)
-                                              && !isinf(exponent)));
+#define NJS_PRE_UNARY                                                         \
+        if (njs_slow_path(!njs_is_numeric(value1))) {                         \
+            ret = njs_value_to_numeric(vm, value1, &numeric1);                \
+            if (njs_slow_path(ret != NJS_OK)) {                               \
+                goto error;                                                   \
+            }                                                                 \
+                                                                              \
+            value1 = &numeric1;                                               \
+        }                                                                     \
+                                                                              \
+        num = njs_number(value1);                                             \
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
 
-                    num = valid ? pow(num, exponent) : NAN;
-                    break;
+    CASE (NJS_VMCODE_UNARY_NEGATION):
+        njs_vmcode_debug_opcode();
 
-                case NJS_VMCODE_DIVISION:
-                    num /= njs_number(value2);
-                    break;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                case NJS_VMCODE_REMAINDER:
-                    num = fmod(num, njs_number(value2));
-                    break;
+        NJS_PRE_UNARY;
 
-                case NJS_VMCODE_BITWISE_AND:
-                case NJS_VMCODE_BITWISE_OR:
-                case NJS_VMCODE_BITWISE_XOR:
-                    i32 = njs_number_to_int32(njs_number(value2));
+        num = -num;
 
-                    switch (op) {
-                    case NJS_VMCODE_BITWISE_AND:
-                        i32 &= njs_number_to_int32(num);
-                        break;
+        njs_set_number(retval, num);
 
-                    case NJS_VMCODE_BITWISE_OR:
-                        i32 |= njs_number_to_int32(num);
-                        break;
+        pc += sizeof(njs_vmcode_2addr_t);
+        NEXT;
 
-                    case NJS_VMCODE_BITWISE_XOR:
-                        i32 ^= njs_number_to_int32(num);
-                        break;
-                    }
+    CASE (NJS_VMCODE_UNARY_PLUS):
+        njs_vmcode_debug_opcode();
 
-                    njs_set_int32(retval, i32);
-                    goto next;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                default:
-                    u32 = njs_number_to_uint32(njs_number(value2)) & 0x1f;
+        NJS_PRE_UNARY;
 
-                    switch (op) {
-                    case NJS_VMCODE_LEFT_SHIFT:
-                    case NJS_VMCODE_RIGHT_SHIFT:
-                        i32 = njs_number_to_int32(num);
+        njs_set_number(retval, num);
 
-                        if (op == NJS_VMCODE_LEFT_SHIFT) {
-                            /* Shifting of negative numbers is undefined. */
-                            i32 = (uint32_t) i32 << u32;
-                        } else {
-                            i32 >>= u32;
-                        }
+        pc += sizeof(njs_vmcode_2addr_t);
+        NEXT;
 
-                        njs_set_int32(retval, i32);
-                        break;
+    CASE (NJS_VMCODE_BITWISE_NOT):
+        njs_vmcode_debug_opcode();
 
-                    default: /* NJS_VMCODE_UNSIGNED_RIGHT_SHIFT */
-                        njs_set_uint32(retval,
-                                       njs_number_to_uint32(num) >> u32);
-                    }
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                    goto next;
-                }
+        NJS_PRE_UNARY;
 
-                njs_set_number(retval, num);
-                goto next;
+        njs_set_int32(retval, ~njs_number_to_uint32(num));
 
-            case NJS_VMCODE_OBJECT_COPY:
-                ret = njs_vmcode_object_copy(vm, value1, value2);
-                break;
+        pc += sizeof(njs_vmcode_2addr_t);
+        NEXT;
 
-            case NJS_VMCODE_TEMPLATE_LITERAL:
-                ret = njs_vmcode_template_literal(vm, value1, value2);
-                break;
+    CASE (NJS_VMCODE_LOGICAL_NOT):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_PROPERTY_IN:
-                ret = njs_vmcode_property_in(vm, value1, value2);
-                break;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
 
-            case NJS_VMCODE_PROPERTY_DELETE:
-                ret = njs_value_property_delete(vm, value1, value2, NULL, 1);
-                if (njs_fast_path(ret != NJS_ERROR)) {
-                    vm->retval = njs_value_true;
+        njs_set_boolean(retval, !njs_is_true(value1));
 
-                    ret = sizeof(njs_vmcode_3addr_t);
-                }
+        pc += sizeof(njs_vmcode_2addr_t);
+        NEXT;
 
-                break;
+    CASE (NJS_VMCODE_OBJECT):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_PROPERTY_FOREACH:
-                ret = njs_vmcode_property_foreach(vm, value1, value2, pc);
-                break;
+        ret = njs_vmcode_object(vm);
 
-            case NJS_VMCODE_STRICT_EQUAL:
-            case NJS_VMCODE_STRICT_NOT_EQUAL:
-                ret = njs_values_strict_equal(value1, value2);
+        if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+            goto error;
+        }
 
-                ret ^= op - NJS_VMCODE_STRICT_EQUAL;
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
 
-                njs_vmcode_operand(vm, vmcode->operand1, retval);
-                njs_set_boolean(retval, ret);
+        BREAK;
 
-                pc += sizeof(njs_vmcode_3addr_t);
-                goto next;
+    CASE (NJS_VMCODE_ARRAY):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_TEST_IF_TRUE:
-            case NJS_VMCODE_TEST_IF_FALSE:
-            case NJS_VMCODE_COALESCE:
-                if (op == NJS_VMCODE_COALESCE) {
-                    ret = !njs_is_null_or_undefined(value1);
+        ret = njs_vmcode_array(vm, pc);
 
-                } else {
-                    ret = njs_is_true(value1);
-                    ret ^= op - NJS_VMCODE_TEST_IF_TRUE;
-                }
+        if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+            goto error;
+        }
 
-                if (ret) {
-                    test_jump = (njs_vmcode_test_jump_t *) pc;
-                    ret = test_jump->offset;
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
 
-                } else {
-                    ret = sizeof(njs_vmcode_3addr_t);
-                }
+        BREAK;
 
-                njs_vmcode_operand(vm, vmcode->operand1, retval);
-                *retval = *value1;
+    CASE (NJS_VMCODE_FUNCTION):
+        njs_vmcode_debug_opcode();
 
-                pc += ret;
-                goto next;
+        ret = njs_vmcode_function(vm, pc);
 
-            case NJS_VMCODE_UNARY_PLUS:
-            case NJS_VMCODE_UNARY_NEGATION:
-            case NJS_VMCODE_BITWISE_NOT:
-                if (njs_slow_path(!njs_is_numeric(value1))) {
-                    ret = njs_value_to_numeric(vm, value1, &numeric1);
-                    if (njs_slow_path(ret != NJS_OK)) {
-                        goto error;
-                    }
+        if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+            goto error;
+        }
 
-                    value1 = &numeric1;
-                }
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
 
-                num = njs_number(value1);
-                njs_vmcode_operand(vm, vmcode->operand1, retval);
+        BREAK;
 
-                switch (op) {
-                case NJS_VMCODE_UNARY_NEGATION:
-                    num = -num;
+    CASE (NJS_VMCODE_REGEXP):
+        njs_vmcode_debug_opcode();
 
-                    /* Fall through. */
-                case NJS_VMCODE_UNARY_PLUS:
-                    njs_set_number(retval, num);
-                    break;
+        ret = njs_vmcode_regexp(vm, pc);
 
-                case NJS_VMCODE_BITWISE_NOT:
-                    njs_set_int32(retval, ~njs_number_to_uint32(num));
-                }
+        if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
+
+        BREAK;
+
+    CASE (NJS_VMCODE_INSTANCE_OF):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        ret = njs_vmcode_instance_of(vm, value1, value2);
+
+        if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
+
+        BREAK;
+
+    CASE (NJS_VMCODE_TYPEOF):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        ret = njs_vmcode_typeof(vm, value1, NULL);
+
+        if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
+            goto error;
+        }
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
+
+        BREAK;
+
+    CASE (NJS_VMCODE_VOID):
+        njs_vmcode_debug_opcode();
+
+        njs_set_undefined(&vm->retval);
+
+        ret = sizeof(njs_vmcode_2addr_t);
+
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
+
+        BREAK;
+
+    CASE (NJS_VMCODE_DELETE):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        njs_release(vm, value1);
+        vm->retval = njs_value_true;
+
+        ret = sizeof(njs_vmcode_2addr_t);
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
+
+        BREAK;
 
-                pc += sizeof(njs_vmcode_2addr_t);
-                goto next;
+    CASE (NJS_VMCODE_DEBUGGER):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_LOGICAL_NOT:
-                njs_vmcode_operand(vm, vmcode->operand1, retval);
-                njs_set_boolean(retval, !njs_is_true(value1));
+        ret = njs_vmcode_debugger(vm);
 
-                pc += sizeof(njs_vmcode_2addr_t);
-                goto next;
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
+        njs_release(vm, retval);
+        *retval = vm->retval;
 
-            case NJS_VMCODE_OBJECT:
-                ret = njs_vmcode_object(vm);
-                break;
+        BREAK;
 
-            case NJS_VMCODE_ARRAY:
-                ret = njs_vmcode_array(vm, pc);
-                break;
+    CASE (NJS_VMCODE_PUT_ARG):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_FUNCTION:
-                ret = njs_vmcode_function(vm, pc);
-                break;
+        put_arg = (njs_vmcode_1addr_t *) pc;
+        native = vm->top_frame;
+
+        value1 = &native->arguments[native->put_args++];
+        njs_vmcode_operand(vm, put_arg->index, value2);
+
+        njs_value_assign(value1, value2);
+
+        ret = sizeof(njs_vmcode_1addr_t);
+        BREAK;
 
-            case NJS_VMCODE_REGEXP:
-                ret = njs_vmcode_regexp(vm, pc);
-                break;
+    CASE (NJS_VMCODE_STOP):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_INSTANCE_OF:
-                ret = njs_vmcode_instance_of(vm, value1, value2);
-                break;
+        njs_vmcode_operand(vm, vmcode->operand1, value2);
+        vm->retval = *value2;
 
-            case NJS_VMCODE_TYPEOF:
-                ret = njs_vmcode_typeof(vm, value1, value2);
-                break;
+        njs_vmcode_debug(vm, pc, "EXIT STOP");
 
-            case NJS_VMCODE_VOID:
-                njs_set_undefined(&vm->retval);
+        return NJS_OK;
 
-                ret = sizeof(njs_vmcode_2addr_t);
-                break;
+    CASE (NJS_VMCODE_JUMP):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_DELETE:
-                njs_release(vm, value1);
-                vm->retval = njs_value_true;
+        ret = (njs_jump_off_t) vmcode->operand1;
+        BREAK;
 
-                ret = sizeof(njs_vmcode_2addr_t);
-                break;
+    CASE (NJS_VMCODE_PROPERTY_SET):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_DEBUGGER:
-                ret = njs_vmcode_debugger(vm);
-                break;
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+        njs_vmcode_operand(vm, vmcode->operand1, retval);
 
-            default:
-                njs_internal_error(vm, "%d has retval", op);
+        if (njs_slow_path(!njs_is_index_or_key(value2))) {
+            if (njs_slow_path(njs_is_null_or_undefined(value1))) {
+                (void) njs_throw_cannot_property(vm, value1, value2, "set");
                 goto error;
             }
 
-            if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) {
-                break;
+            njs_value_assign(&primitive1, value1);
+            ret = njs_value_to_key(vm, &primitive2, value2);
+            if (njs_slow_path(ret != NJS_OK)) {
+                goto error;
             }
 
-            njs_vmcode_operand(vm, vmcode->operand1, retval);
-            njs_release(vm, retval);
-            *retval = vm->retval;
+            value1 = &primitive1;
+            value2 = &primitive2;
+        }
+
+        ret = njs_value_property_set(vm, value1, value2, retval);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
+
+        ret = sizeof(njs_vmcode_prop_set_t);
+        BREAK;
+
+    CASE (NJS_VMCODE_PROPERTY_ACCESSOR):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        accessor = (njs_vmcode_prop_accessor_t *) pc;
+        njs_vmcode_operand(vm, accessor->value, function);
+
+        ret = njs_value_to_key(vm, &name, value2);
+        if (njs_slow_path(ret != NJS_OK)) {
+            njs_internal_error(vm, "failed conversion of type \"%s\" "
+                               "to string while property define",
+                               njs_type_string(value2->type));
+            goto error;
+        }
+
+        ret = njs_object_prop_define(vm, value1, &name, function,
+                                     accessor->type);
+        if (njs_slow_path(ret != NJS_OK)) {
+            goto error;
+        }
+
+        ret = sizeof(njs_vmcode_prop_accessor_t);
+        BREAK;
+
+    CASE (NJS_VMCODE_IF_TRUE_JUMP):
+        njs_vmcode_debug_opcode();
+
+        value2 = (njs_value_t *) vmcode->operand1;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        ret = njs_is_true(value1);
+
+        ret = ret ? (njs_jump_off_t) value2
+                  : (njs_jump_off_t) sizeof(njs_vmcode_cond_jump_t);
+
+        BREAK;
+
+    CASE (NJS_VMCODE_IF_FALSE_JUMP):
+        njs_vmcode_debug_opcode();
+
+        value2 = (njs_value_t *) vmcode->operand1;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        ret = njs_is_true(value1);
+
+        ret = !ret ? (njs_jump_off_t) value2
+                   : (njs_jump_off_t) sizeof(njs_vmcode_cond_jump_t);
+
+        BREAK;
+
+    CASE (NJS_VMCODE_IF_EQUAL_JUMP):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
+
+        if (njs_values_strict_equal(value1, value2)) {
+            equal = (njs_vmcode_equal_jump_t *) pc;
+            ret = equal->offset;
 
         } else {
+            ret = sizeof(njs_vmcode_3addr_t);
+        }
+
+        BREAK;
 
-            switch (op) {
-            case NJS_VMCODE_PUT_ARG:
-                put_arg = (njs_vmcode_1addr_t *) pc;
-                native = vm->top_frame;
+    CASE (NJS_VMCODE_PROPERTY_INIT):
+        njs_vmcode_debug_opcode();
 
-                value1 = &native->arguments[native->put_args++];
-                njs_vmcode_operand(vm, put_arg->index, value2);
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                njs_value_assign(value1, value2);
+        set = (njs_vmcode_prop_set_t *) pc;
+        njs_vmcode_operand(vm, set->value, retval);
+        ret = njs_vmcode_property_init(vm, value1, value2, retval);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
 
-                ret = sizeof(njs_vmcode_1addr_t);
-                break;
+        BREAK;
 
-            case NJS_VMCODE_STOP:
-                njs_vmcode_operand(vm, (njs_index_t) value2, value2);
-                vm->retval = *value2;
+    CASE (NJS_VMCODE_RETURN):
+        njs_vmcode_debug_opcode();
 
-                njs_vmcode_debug(vm, pc, "EXIT STOP");
+        value2 = (njs_value_t *) vmcode->operand1;
 
-                return NJS_OK;
+        njs_vmcode_operand(vm, (njs_index_t) value2, value2);
 
-            case NJS_VMCODE_JUMP:
-                ret = (njs_jump_off_t) value2;
-                break;
+        njs_vmcode_debug(vm, pc, "EXIT RETURN");
 
-            case NJS_VMCODE_PROPERTY_SET:
-                set = (njs_vmcode_prop_set_t *) pc;
-                njs_vmcode_operand(vm, set->value, retval);
+        return njs_vmcode_return(vm, NULL, value2);
 
-                if (njs_slow_path(!njs_is_index_or_key(value2))) {
-                    if (njs_slow_path(njs_is_null_or_undefined(value1))) {
-                        (void) njs_throw_cannot_property(vm, value1, value2,
-                                                         "set");
-                        goto error;
-                    }
+    CASE (NJS_VMCODE_FUNCTION_COPY):
+        njs_vmcode_debug_opcode();
 
-                    njs_value_assign(&primitive1, value1);
-                    ret = njs_value_to_key(vm, &primitive2, value2);
-                    if (njs_slow_path(ret != NJS_OK)) {
-                        goto error;
-                    }
+        fcopy = (njs_vmcode_function_copy_t *) pc;
+        ret = njs_vmcode_function_copy(vm, fcopy->function, fcopy->retval);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
 
-                    value1 = &primitive1;
-                    value2 = &primitive2;
-                }
+        BREAK;
 
-                ret = njs_value_property_set(vm, value1, value2, retval);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+    CASE (NJS_VMCODE_FUNCTION_FRAME):
+        njs_vmcode_debug_opcode();
 
-                ret = sizeof(njs_vmcode_prop_set_t);
-                break;
+        value2 = (njs_value_t *) vmcode->operand1;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-            case NJS_VMCODE_PROPERTY_ACCESSOR:
-                accessor = (njs_vmcode_prop_accessor_t *) pc;
-                njs_vmcode_operand(vm, accessor->value, function);
+        function_frame = (njs_vmcode_function_frame_t *) pc;
 
-                ret = njs_value_to_key(vm, &name, value2);
-                if (njs_slow_path(ret != NJS_OK)) {
-                    njs_internal_error(vm, "failed conversion of type \"%s\" "
-                                       "to string while property define",
-                                       njs_type_string(value2->type));
-                    goto error;
-                }
+        ret = njs_function_frame_create(vm, value1, &njs_value_undefined,
+                                        (uintptr_t) value2,
+                                        function_frame->ctor);
 
-                ret = njs_object_prop_define(vm, value1, &name, function,
-                                             accessor->type);
-                if (njs_slow_path(ret != NJS_OK)) {
-                    goto error;
-                }
+        if (njs_slow_path(ret != NJS_OK)) {
+            goto error;
+        }
 
-                ret = sizeof(njs_vmcode_prop_accessor_t);
-                break;
+        ret = sizeof(njs_vmcode_function_frame_t);
+        BREAK;
 
-            case NJS_VMCODE_IF_TRUE_JUMP:
-            case NJS_VMCODE_IF_FALSE_JUMP:
-                ret = njs_is_true(value1);
+    CASE (NJS_VMCODE_METHOD_FRAME):
+        njs_vmcode_debug_opcode();
 
-                ret ^= op - NJS_VMCODE_IF_TRUE_JUMP;
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                ret = ret ? (njs_jump_off_t) value2
-                          : (njs_jump_off_t) sizeof(njs_vmcode_cond_jump_t);
+        method_frame = (njs_vmcode_method_frame_t *) pc;
 
-                break;
+        if (njs_slow_path(!njs_is_key(value2))) {
+            if (njs_slow_path(njs_is_null_or_undefined(value1))) {
+                (void) njs_throw_cannot_property(vm, value1, value2, "get");
+                goto error;
+            }
 
-            case NJS_VMCODE_IF_EQUAL_JUMP:
-                if (njs_values_strict_equal(value1, value2)) {
-                    equal = (njs_vmcode_equal_jump_t *) pc;
-                    ret = equal->offset;
+            ret = njs_value_to_key(vm, &primitive1, value2);
+            if (njs_slow_path(ret != NJS_OK)) {
+                goto error;
+            }
 
-                } else {
-                    ret = sizeof(njs_vmcode_3addr_t);
-                }
+            value2 = &primitive1;
+        }
 
-                break;
+        ret = njs_value_property(vm, value1, value2, &dst);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
 
-            case NJS_VMCODE_PROPERTY_INIT:
-                set = (njs_vmcode_prop_set_t *) pc;
-                njs_vmcode_operand(vm, set->value, retval);
-                ret = njs_vmcode_property_init(vm, value1, value2, retval);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+        if (njs_slow_path(!njs_is_function(&dst))) {
+            ret = njs_value_to_key(vm, &dst, value2);
+            if (njs_slow_path(ret != NJS_OK)) {
+                goto error;
+            }
 
-                break;
+            njs_key_string_get(vm, &dst, &string);
+            njs_type_error(vm,
+                       "(intermediate value)[\"%V\"] is not a function",
+                       &string);
+            goto error;
+        }
 
-            case NJS_VMCODE_RETURN:
-                njs_vmcode_operand(vm, (njs_index_t) value2, value2);
+        ret = njs_function_frame_create(vm, &dst, value1, method_frame->nargs,
+                                        method_frame->ctor);
 
-                njs_vmcode_debug(vm, pc, "EXIT RETURN");
+        if (njs_slow_path(ret != NJS_OK)) {
+            goto error;
+        }
 
-                return njs_vmcode_return(vm, NULL, value2);
+        ret = sizeof(njs_vmcode_method_frame_t);
+        BREAK;
 
-            case NJS_VMCODE_FUNCTION_COPY:
-                fcopy = (njs_vmcode_function_copy_t *) pc;
-                ret = njs_vmcode_function_copy(vm, fcopy->function,
-                                               fcopy->retval);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+    CASE (NJS_VMCODE_FUNCTION_CALL):
+        njs_vmcode_debug_opcode();
 
-                break;
+        value2 = (njs_value_t *) vmcode->operand1;
 
-            case NJS_VMCODE_FUNCTION_FRAME:
-                function_frame = (njs_vmcode_function_frame_t *) pc;
+        vm->active_frame->native.pc = pc;
 
-                /* TODO: external object instead of void this. */
+        njs_vmcode_operand(vm, (njs_index_t) value2, value2);
 
-                ret = njs_function_frame_create(vm, value1,
-                                                &njs_value_undefined,
-                                                (uintptr_t) value2,
-                                                function_frame->ctor);
+        ret = njs_function_frame_invoke(vm, value2);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
 
-                if (njs_slow_path(ret != NJS_OK)) {
-                    goto error;
-                }
+        njs_vmcode_debug(vm, pc, "RESUME");
 
-                ret = sizeof(njs_vmcode_function_frame_t);
-                break;
+        ret = sizeof(njs_vmcode_function_call_t);
+        BREAK;
 
-            case NJS_VMCODE_METHOD_FRAME:
-                method_frame = (njs_vmcode_method_frame_t *) pc;
+    CASE (NJS_VMCODE_PROPERTY_NEXT):
+        njs_vmcode_debug_opcode();
 
-                if (njs_slow_path(!njs_is_key(value2))) {
-                    if (njs_slow_path(njs_is_null_or_undefined(value1))) {
-                        (void) njs_throw_cannot_property(vm, value1, value2,
-                                                         "get");
-                        goto error;
-                    }
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                    ret = njs_value_to_key(vm, &primitive1, value2);
-                    if (njs_slow_path(ret != NJS_OK)) {
-                        goto error;
-                    }
+        pnext = (njs_vmcode_prop_next_t *) pc;
+        retval = njs_scope_value(vm, pnext->retval);
 
-                    value2 = &primitive1;
-                }
+        njs_assert(njs_is_data(value2, NJS_DATA_TAG_FOREACH_NEXT));
+        next = njs_data(value2);
 
-                ret = njs_value_property(vm, value1, value2, &dst);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+        if (next->index < next->array->length) {
+            *retval = next->array->start[next->index++];
 
-                if (njs_slow_path(!njs_is_function(&dst))) {
-                    ret = njs_value_to_key(vm, &dst, value2);
-                    if (njs_slow_path(ret != NJS_OK)) {
-                        goto error;
-                    }
-
-                    njs_key_string_get(vm, &dst, &string);
-                    njs_type_error(vm,
-                               "(intermediate value)[\"%V\"] is not a function",
-                               &string);
-                    goto error;
-                }
+            ret = pnext->offset;
+            BREAK;
+        }
 
-                ret = njs_function_frame_create(vm, &dst, value1,
-                                                method_frame->nargs,
-                                                method_frame->ctor);
+        njs_mp_free(vm->mem_pool, next);
 
-                if (njs_slow_path(ret != NJS_OK)) {
-                    goto error;
-                }
+        ret = sizeof(njs_vmcode_prop_next_t);
+        BREAK;
 
-                ret = sizeof(njs_vmcode_method_frame_t);
-                break;
+    CASE (NJS_VMCODE_ARGUMENTS):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_FUNCTION_CALL:
-                vm->active_frame->native.pc = pc;
+        ret = njs_vmcode_arguments(vm, pc);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
 
-                njs_vmcode_operand(vm, (njs_index_t) value2, value2);
+        BREAK;
 
-                ret = njs_function_frame_invoke(vm, value2);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+    CASE (NJS_VMCODE_TO_PROPERTY_KEY):
+        njs_vmcode_debug_opcode();
 
-                njs_vmcode_debug(vm, pc, "RESUME");
+        value2 = (njs_value_t *) vmcode->operand1;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                ret = sizeof(njs_vmcode_function_call_t);
-                break;
+        njs_vmcode_operand(vm, (njs_index_t) value2, retval);
 
-            case NJS_VMCODE_PROPERTY_NEXT:
-                pnext = (njs_vmcode_prop_next_t *) pc;
-                retval = njs_scope_value(vm, pnext->retval);
+        ret = njs_value_to_key(vm, retval, value1);
+        if (njs_fast_path(ret == NJS_ERROR)) {
+            goto error;
+        }
 
-                njs_assert(njs_is_data(value2, NJS_DATA_TAG_FOREACH_NEXT));
-                next = njs_data(value2);
+        ret = sizeof(njs_vmcode_2addr_t);
+        BREAK;
 
-                if (next->index < next->array->length) {
-                    *retval = next->array->start[next->index++];
+    CASE (NJS_VMCODE_TO_PROPERTY_KEY_CHK):
+        njs_vmcode_debug_opcode();
 
-                    ret = pnext->offset;
-                    break;
-                }
+        value2 = (njs_value_t *) vmcode->operand1;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                njs_mp_free(vm->mem_pool, next);
+        njs_vmcode_operand(vm, (njs_index_t) value2, retval);
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
 
-                ret = sizeof(njs_vmcode_prop_next_t);
-                break;
+        if (njs_slow_path(njs_is_null_or_undefined(value2))) {
+            (void) njs_throw_cannot_property(vm, value2, value1, "get");
+            goto error;
+        }
 
-            case NJS_VMCODE_ARGUMENTS:
-                ret = njs_vmcode_arguments(vm, pc);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+        ret = njs_value_to_key(vm, retval, value1);
+        if (njs_fast_path(ret == NJS_ERROR)) {
+            goto error;
+        }
 
-                break;
+        ret = sizeof(njs_vmcode_3addr_t);
+        BREAK;
 
-            case NJS_VMCODE_TO_PROPERTY_KEY:
-            case NJS_VMCODE_TO_PROPERTY_KEY_CHK:
-                njs_vmcode_operand(vm, (njs_index_t) value2, retval);
+    CASE (NJS_VMCODE_SET_FUNCTION_NAME):
+        njs_vmcode_debug_opcode();
 
-                if (op == NJS_VMCODE_TO_PROPERTY_KEY_CHK) {
-                    njs_vmcode_operand(vm, vmcode->operand3, value2);
+        value2 = (njs_value_t *) vmcode->operand1;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                    if (njs_slow_path(njs_is_null_or_undefined(value2))) {
-                        (void) njs_throw_cannot_property(vm, value2, value1,
-                                                         "get");
-                        goto error;
-                    }
-                }
+        njs_vmcode_operand(vm, (njs_index_t) value2, value2);
 
-                ret = njs_value_to_key(vm, retval, value1);
-                if (njs_fast_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+        njs_assert(njs_is_function(value2));
 
-                ret = (op == NJS_VMCODE_TO_PROPERTY_KEY)
-                       ? sizeof(njs_vmcode_2addr_t)
-                       : sizeof(njs_vmcode_3addr_t);
-                break;
+        ret = njs_function_name_set(vm, njs_function(value2), value1, NULL);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return ret;
+        }
 
-            case NJS_VMCODE_SET_FUNCTION_NAME:
-                njs_vmcode_operand(vm, (njs_index_t) value2, value2);
+        ret = sizeof(njs_vmcode_2addr_t);
+        BREAK;
 
-                njs_assert(njs_is_function(value2));
 
-                ret = njs_function_name_set(vm, njs_function(value2), value1,
-                                            NULL);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    return ret;
-                }
+    CASE (NJS_VMCODE_PROTO_INIT):
+        njs_vmcode_debug_opcode();
 
-                ret = sizeof(njs_vmcode_2addr_t);
-                break;
+        njs_vmcode_operand(vm, vmcode->operand3, value2);
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-            case NJS_VMCODE_PROTO_INIT:
-                set = (njs_vmcode_prop_set_t *) pc;
-                njs_vmcode_operand(vm, set->value, retval);
-                ret = njs_vmcode_proto_init(vm, value1, value2, retval);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+        set = (njs_vmcode_prop_set_t *) pc;
+        njs_vmcode_operand(vm, set->value, retval);
+        ret = njs_vmcode_proto_init(vm, value1, value2, retval);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
 
-                break;
+        BREAK;
 
-            case NJS_VMCODE_IMPORT:
-                import = (njs_vmcode_import_t *) pc;
-                retval = njs_scope_value(vm, import->retval);
-                ret = njs_vmcode_import(vm, import->module, retval);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+    CASE (NJS_VMCODE_IMPORT):
+        njs_vmcode_debug_opcode();
 
-                break;
+        import = (njs_vmcode_import_t *) pc;
+        retval = njs_scope_value(vm, import->retval);
+        ret = njs_vmcode_import(vm, import->module, retval);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
 
-            case NJS_VMCODE_AWAIT:
-                await = (njs_vmcode_await_t *) pc;
+        BREAK;
 
-                ret = njs_vmcode_await(vm, await, promise_cap, async_ctx);
+    CASE (NJS_VMCODE_AWAIT):
+        njs_vmcode_debug_opcode();
 
-                njs_vmcode_debug(vm, pc, "EXIT AWAIT");
+        await = (njs_vmcode_await_t *) pc;
 
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+        ret = njs_vmcode_await(vm, await, promise_cap, async_ctx);
 
-                return ret;
+        njs_vmcode_debug(vm, pc, "EXIT AWAIT");
 
-            case NJS_VMCODE_TRY_START:
-                ret = njs_vmcode_try_start(vm, value1, value2, pc);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
 
-                break;
+        return ret;
 
-            case NJS_VMCODE_THROW:
-                njs_vmcode_operand(vm, (njs_index_t) value2, value2);
-                vm->retval = *value2;
-                goto error;
+    CASE (NJS_VMCODE_TRY_START):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_TRY_BREAK:
-                try_trampoline = (njs_vmcode_try_trampoline_t *) pc;
-                value1 = njs_scope_value(vm, try_trampoline->exit_value);
-
-                ret = njs_vmcode_try_break(vm, value1, value2);
-                break;
-
-            case NJS_VMCODE_TRY_CONTINUE:
-                try_trampoline = (njs_vmcode_try_trampoline_t *) pc;
-                value1 = njs_scope_value(vm, try_trampoline->exit_value);
-
-                ret = njs_vmcode_try_continue(vm, value1, value2);
-                break;
-
-            case NJS_VMCODE_TRY_END:
-                ret = njs_vmcode_try_end(vm, value1, value2);
-                break;
-
-            /*
-             * njs_vmcode_catch() is set on the start of a "catch" block to
-             * store exception and to remove a "try" block if there is no
-             * "finally" block or to update a catch address to the start of
-             * a "finally" block.
-             * njs_vmcode_catch() is set on the start of a "finally" block
-             * to store uncaught exception and to remove a "try" block.
-             */
-            case NJS_VMCODE_CATCH:
-                *value1 = vm->retval;
-
-                if ((njs_jump_off_t) value2 == sizeof(njs_vmcode_catch_t)) {
-                    ret = njs_vmcode_try_end(vm, value1, value2);
-
-                } else {
-                    frame = (njs_frame_t *) vm->top_frame;
-                    frame->exception.catch = pc + (njs_jump_off_t) value2;
-                    ret = sizeof(njs_vmcode_catch_t);
-                }
+        value2 = (njs_value_t *) vmcode->operand1;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                break;
+        ret = njs_vmcode_try_start(vm, value1, value2, pc);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            goto error;
+        }
 
-            case NJS_VMCODE_FINALLY:
-                finally = (njs_vmcode_finally_t *) pc;
-                value1 = njs_scope_value(vm, finally->exit_value);
+        BREAK;
 
-                ret = njs_vmcode_finally(vm, value1, value2, pc);
+    CASE (NJS_VMCODE_THROW):
+        njs_vmcode_debug_opcode();
 
-                switch (ret) {
-                case NJS_OK:
+        value2 = (njs_value_t *) vmcode->operand1;
 
-                    njs_vmcode_debug(vm, pc, "EXIT FINALLY");
+        njs_vmcode_operand(vm, (njs_index_t) value2, value2);
+        vm->retval = *value2;
 
-                    return NJS_OK;
-                case NJS_ERROR:
-                    goto error;
-                }
+        goto error;
 
-                break;
+    CASE (NJS_VMCODE_TRY_BREAK):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_LET:
-                var = (njs_vmcode_variable_t *) pc;
-                value1 = njs_scope_value(vm, var->dst);
+        value2 = (njs_value_t *) vmcode->operand1;
 
-                if (njs_is_valid(value1)) {
-                    value1 = njs_mp_alloc(vm->mem_pool, sizeof(njs_value_t));
-                    if (njs_slow_path(value1 == NULL)) {
-                        njs_memory_error(vm);
-                        goto error;
-                    }
+        try_trampoline = (njs_vmcode_try_trampoline_t *) pc;
+        value1 = njs_scope_value(vm, try_trampoline->exit_value);
 
-                    njs_scope_value_set(vm, var->dst, value1);
-                }
+        ret = njs_vmcode_try_break(vm, value1, value2);
+        BREAK;
 
-                njs_set_undefined(value1);
+    CASE (NJS_VMCODE_TRY_CONTINUE):
+        njs_vmcode_debug_opcode();
 
-                ret = sizeof(njs_vmcode_variable_t);
-                break;
+        value2 = (njs_value_t *) vmcode->operand1;
 
-            case NJS_VMCODE_LET_UPDATE:
-                var = (njs_vmcode_variable_t *) pc;
-                value2 = njs_scope_value(vm, var->dst);
+        try_trampoline = (njs_vmcode_try_trampoline_t *) pc;
+        value1 = njs_scope_value(vm, try_trampoline->exit_value);
 
-                value1 = njs_mp_alloc(vm->mem_pool, sizeof(njs_value_t));
-                if (njs_slow_path(value1 == NULL)) {
-                    njs_memory_error(vm);
-                    goto error;
-                }
+        ret = njs_vmcode_try_continue(vm, value1, value2);
+        BREAK;
 
-                *value1 = *value2;
+    CASE (NJS_VMCODE_TRY_END):
+        njs_vmcode_debug_opcode();
 
-                njs_scope_value_set(vm, var->dst, value1);
+        ret = njs_vmcode_try_end(vm, NULL, (njs_value_t *) vmcode->operand1);
+        BREAK;
 
-                ret = sizeof(njs_vmcode_variable_t);
-                break;
+    /*
+     * njs_vmcode_catch() is set on the start of a "catch" block to
+     * store exception and to remove a "try" block if there is no
+     * "finally" block or to update a catch address to the start of
+     * a "finally" block.
+     * njs_vmcode_catch() is set on the start of a "finally" block
+     * to store uncaught exception and to remove a "try" block.
+     */
+    CASE (NJS_VMCODE_CATCH):
+        njs_vmcode_debug_opcode();
 
-            case NJS_VMCODE_INITIALIZATION_TEST:
-                var = (njs_vmcode_variable_t *) pc;
-                value1 = njs_scope_value(vm, var->dst);
+        value2 = (njs_value_t *) vmcode->operand1;
+        njs_vmcode_operand(vm, vmcode->operand2, value1);
 
-                if (njs_is_valid(value1)) {
-                    ret = sizeof(njs_vmcode_variable_t);
-                    break;
-                }
+        *value1 = vm->retval;
 
-                /* Fall through. */
+        if ((njs_jump_off_t) value2 == sizeof(njs_vmcode_catch_t)) {
+            ret = njs_vmcode_try_end(vm, value1, value2);
 
-            case NJS_VMCODE_NOT_INITIALIZED:
-                njs_reference_error(vm, "cannot access variable "
-                                        "before initialization");
-                goto error;
+        } else {
+            frame = (njs_frame_t *) vm->top_frame;
+            frame->exception.catch = pc + (njs_jump_off_t) value2;
+            ret = sizeof(njs_vmcode_catch_t);
+        }
 
-            case NJS_VMCODE_ERROR:
-                njs_vmcode_error(vm, pc);
-                goto error;
+        BREAK;
 
-            case NJS_VMCODE_ASSIGNMENT_ERROR:
-                njs_type_error(vm, "assignment to constant variable");
-                goto error;
+    CASE (NJS_VMCODE_FINALLY):
+        njs_vmcode_debug_opcode();
+
+        value2 = (njs_value_t *) vmcode->operand1;
+
+        finally = (njs_vmcode_finally_t *) pc;
+        value1 = njs_scope_value(vm, finally->exit_value);
+
+        ret = njs_vmcode_finally(vm, NULL, value2, pc);
+
+        switch (ret) {
+        case NJS_OK:
+            njs_vmcode_debug(vm, pc, "EXIT FINALLY");
+
+            return NJS_OK;
+        case NJS_ERROR:
+            goto error;
+        }
 
-            default:
-                njs_internal_error(vm, "%d has NO retval", op);
+        BREAK;
+
+    CASE (NJS_VMCODE_LET):
+        njs_vmcode_debug_opcode();
+
+        var = (njs_vmcode_variable_t *) pc;
+        value1 = njs_scope_value(vm, var->dst);
+
+        if (njs_is_valid(value1)) {
+            value1 = njs_mp_alloc(vm->mem_pool, sizeof(njs_value_t));
+            if (njs_slow_path(value1 == NULL)) {
+                njs_memory_error(vm);
                 goto error;
             }
+
+            njs_scope_value_set(vm, var->dst, value1);
+        }
+
+        njs_set_undefined(value1);
+
+        ret = sizeof(njs_vmcode_variable_t);
+        BREAK;
+
+    CASE (NJS_VMCODE_LET_UPDATE):
+        njs_vmcode_debug_opcode();
+
+        var = (njs_vmcode_variable_t *) pc;
+        value2 = njs_scope_value(vm, var->dst);
+
+        value1 = njs_mp_alloc(vm->mem_pool, sizeof(njs_value_t));
+        if (njs_slow_path(value1 == NULL)) {
+            njs_memory_error(vm);
+            goto error;
+        }
+
+        *value1 = *value2;
+
+        njs_scope_value_set(vm, var->dst, value1);
+
+        ret = sizeof(njs_vmcode_variable_t);
+        BREAK;
+
+    CASE (NJS_VMCODE_INITIALIZATION_TEST):
+        njs_vmcode_debug_opcode();
+
+        var = (njs_vmcode_variable_t *) pc;
+        value1 = njs_scope_value(vm, var->dst);
+
+        if (njs_is_valid(value1)) {
+            ret = sizeof(njs_vmcode_variable_t);
+            BREAK;
         }
 
-        pc += ret;
+        FALLTHROUGH;
+    CASE (NJS_VMCODE_NOT_INITIALIZED):
+        njs_vmcode_debug_opcode();
+
+        njs_reference_error(vm, "cannot access variable before initialization");
+        goto error;
+
+    CASE (NJS_VMCODE_ERROR):
+        njs_vmcode_debug_opcode();
+
+        njs_vmcode_error(vm, pc);
+        goto error;
+
+    CASE (NJS_VMCODE_ASSIGNMENT_ERROR):
+        njs_vmcode_debug_opcode();
+
+        njs_type_error(vm, "assignment to constant variable");
+        goto error;
+
     }
 
 error:
@@ -1114,7 +1827,7 @@ error:
             if (catch != NULL) {
                 pc = catch;
 
-                goto next;
+                NEXT;
             }
         }
 
@@ -1905,7 +2618,7 @@ njs_function_frame_create(njs_vm_t *vm, njs_value_t *value,
 }
 
 
-njs_object_t *
+inline njs_object_t *
 njs_function_new_object(njs_vm_t *vm, njs_value_t *constructor)
 {
     njs_value_t     proto, bound;
index 7353b16847232ad175c3360677270f98165436b6..9fe89f3c1250a55764b023978d819374f5e37c8a 100644 (file)
@@ -46,16 +46,13 @@ enum {
     NJS_VMCODE_METHOD_FRAME,
     NJS_VMCODE_FUNCTION_CALL,
     NJS_VMCODE_PROPERTY_NEXT,
-    NJS_VMCODE_THIS,
     NJS_VMCODE_ARGUMENTS,
     NJS_VMCODE_PROTO_INIT,
     NJS_VMCODE_TO_PROPERTY_KEY,
     NJS_VMCODE_TO_PROPERTY_KEY_CHK,
     NJS_VMCODE_SET_FUNCTION_NAME,
     NJS_VMCODE_IMPORT,
-
     NJS_VMCODE_AWAIT,
-
     NJS_VMCODE_TRY_START,
     NJS_VMCODE_THROW,
     NJS_VMCODE_TRY_BREAK,
@@ -63,21 +60,13 @@ enum {
     NJS_VMCODE_TRY_END,
     NJS_VMCODE_CATCH,
     NJS_VMCODE_FINALLY,
-
     NJS_VMCODE_LET,
     NJS_VMCODE_LET_UPDATE,
     NJS_VMCODE_INITIALIZATION_TEST,
     NJS_VMCODE_NOT_INITIALIZED,
     NJS_VMCODE_ASSIGNMENT_ERROR,
-
     NJS_VMCODE_ERROR,
-
-    NJS_VMCODE_NORET = 127
-};
-
-
-enum {
-    NJS_VMCODE_MOVE = NJS_VMCODE_NORET + 1,
+    NJS_VMCODE_MOVE,
     NJS_VMCODE_PROPERTY_GET,
     NJS_VMCODE_INCREMENT,
     NJS_VMCODE_POST_INCREMENT,
@@ -85,7 +74,6 @@ enum {
     NJS_VMCODE_POST_DECREMENT,
     NJS_VMCODE_TRY_RETURN,
     NJS_VMCODE_GLOBAL_GET,
-
     NJS_VMCODE_LESS,
     NJS_VMCODE_GREATER,
     NJS_VMCODE_LESS_OR_EQUAL,
@@ -93,7 +81,6 @@ enum {
     NJS_VMCODE_ADDITION,
     NJS_VMCODE_EQUAL,
     NJS_VMCODE_NOT_EQUAL,
-
     NJS_VMCODE_SUBSTRACTION,
     NJS_VMCODE_MULTIPLICATION,
     NJS_VMCODE_EXPONENTIATION,
@@ -110,15 +97,11 @@ enum {
     NJS_VMCODE_PROPERTY_IN,
     NJS_VMCODE_PROPERTY_DELETE,
     NJS_VMCODE_PROPERTY_FOREACH,
-
     NJS_VMCODE_STRICT_EQUAL,
     NJS_VMCODE_STRICT_NOT_EQUAL,
-
     NJS_VMCODE_TEST_IF_TRUE,
     NJS_VMCODE_TEST_IF_FALSE,
-
     NJS_VMCODE_COALESCE,
-
     NJS_VMCODE_UNARY_PLUS,
     NJS_VMCODE_UNARY_NEGATION,
     NJS_VMCODE_BITWISE_NOT,
@@ -127,14 +110,12 @@ enum {
     NJS_VMCODE_ARRAY,
     NJS_VMCODE_FUNCTION,
     NJS_VMCODE_REGEXP,
-
     NJS_VMCODE_INSTANCE_OF,
     NJS_VMCODE_TYPEOF,
     NJS_VMCODE_VOID,
     NJS_VMCODE_DELETE,
     NJS_VMCODE_DEBUGGER,
-
-    NJS_VMCODE_NOP = 255
+    NJS_VMCODES
 };
 
 
@@ -457,8 +438,14 @@ njs_object_t *njs_function_new_object(njs_vm_t *vm, njs_value_t *constructor);
                        (code != NULL) ? &code->name : &njs_entry_unknown);    \
         } while (0);                                                          \
     }
+
+#define njs_vmcode_debug_opcode()                                             \
+    if (vm->options.opcode_debug) {                                           \
+        njs_disassemble(pc, NULL, 1, NULL);                                   \
+    }
 #else
 #define njs_vmcode_debug(vm, pc, prefix)
+#define njs_vmcode_debug_opcode()
 #endif
 
 #endif /* _NJS_VMCODE_H_INCLUDED_ */