details: https://hg.nginx.org/njs/rev/86784a68e8c8 branches: changeset: 1984:86784a68e8c8 user: Vadim Zhestikov <v.zhesti...@f5.com> date: Tue Oct 25 06:43:10 2022 -0700 description: Computed goto support added to vmcode.
diffstat: auto/clang | 19 + auto/computed_goto | 25 + auto/help | 4 + auto/options | 4 + auto/summary | 5 + configure | 1 + src/njs_clang.h | 8 + src/njs_disassembler.c | 2 - src/njs_parser.c | 2 +- src/njs_vmcode.c | 2633 ++++++++++++++++++++++++++++++----------------- src/njs_vmcode.h | 29 +- 11 files changed, 1748 insertions(+), 984 deletions(-) diffs (truncated from 2948 to 1000 lines): diff -r ac02f9219df3 -r 86784a68e8c8 auto/clang --- a/auto/clang Mon Oct 24 22:49:55 2022 -0700 +++ b/auto/clang Tue Oct 25 06:43:10 2022 -0700 @@ -142,6 +142,25 @@ njs_feature_test="struct __attribute__(( . 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 -r ac02f9219df3 -r 86784a68e8c8 auto/computed_goto --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/auto/computed_goto Tue Oct 25 06:43:10 2022 -0700 @@ -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 diff -r ac02f9219df3 -r 86784a68e8c8 auto/help --- a/auto/help Mon Oct 24 22:49:55 2022 -0700 +++ b/auto/help Tue Oct 25 06:43:10 2022 -0700 @@ -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. diff -r ac02f9219df3 -r 86784a68e8c8 auto/options --- a/auto/options Mon Oct 24 22:49:55 2022 -0700 +++ b/auto/options Tue Oct 25 06:43:10 2022 -0700 @@ -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 diff -r ac02f9219df3 -r 86784a68e8c8 auto/summary --- a/auto/summary Mon Oct 24 22:49:55 2022 -0700 +++ b/auto/summary Tue Oct 25 06:43:10 2022 -0700 @@ -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" diff -r ac02f9219df3 -r 86784a68e8c8 configure --- a/configure Mon Oct 24 22:49:55 2022 -0700 +++ b/configure Tue Oct 25 06:43:10 2022 -0700 @@ -46,6 +46,7 @@ NJS_LIB_AUX_LIBS= . auto/memalign . auto/getrandom . auto/stat +. auto/computed_goto . auto/explicit_bzero . auto/pcre . auto/readline diff -r ac02f9219df3 -r 86784a68e8c8 src/njs_clang.h --- a/src/njs_clang.h Mon Oct 24 22:49:55 2022 -0700 +++ b/src/njs_clang.h Tue Oct 25 06:43:10 2022 -0700 @@ -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__)) diff -r ac02f9219df3 -r 86784a68e8c8 src/njs_disassembler.c --- a/src/njs_disassembler.c Mon Oct 24 22:49:55 2022 -0700 +++ b/src/njs_disassembler.c Tue Oct 25 06:43:10 2022 -0700 @@ -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), diff -r ac02f9219df3 -r 86784a68e8c8 src/njs_parser.c --- a/src/njs_parser.c Mon Oct 24 22:49:55 2022 -0700 +++ b/src/njs_parser.c Tue Oct 25 06:43:10 2022 -0700 @@ -4527,7 +4527,7 @@ njs_parser_expression_comma(njs_parser_t 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); } diff -r ac02f9219df3 -r 86784a68e8c8 src/njs_vmcode.c --- a/src/njs_vmcode.c Mon Oct 24 22:49:55 2022 -0700 +++ b/src/njs_vmcode.c Tue Oct 25 06:43:10 2022 -0700 @@ -108,7 +108,6 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_c 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_c njs_vmcode_debug(vm, pc, "ENTER"); -next: - - for ( ;; ) { - - vmcode = (njs_vmcode_generic_t *) pc; - - /* - * 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) { - - case NJS_VMCODE_3OPERANDS: - njs_vmcode_operand(vm, vmcode->operand3, value2); - - /* Fall through. */ - - case NJS_VMCODE_2OPERANDS: - njs_vmcode_operand(vm, vmcode->operand2, value1); +#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; } - op = vmcode->code.operation; - - /* - * 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. - */ - -#ifdef NJS_DEBUG_OPCODE - if (vm->options.opcode_debug) { - njs_disassemble(pc, NULL, 1, NULL); + ret = njs_value_property(vm, value1, value2, retval); + if (njs_slow_path(ret == NJS_ERROR)) { + goto error; } -#endif - - if (op > NJS_VMCODE_NORET) { - - if (op == NJS_VMCODE_MOVE) { - njs_vmcode_operand(vm, vmcode->operand1, retval); - *retval = *value1; - - pc += sizeof(njs_vmcode_move_t); - goto next; + + 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; } - if (op == NJS_VMCODE_PROPERTY_GET) { - 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); - goto next; + 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; } - 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); - } - - njs_set_number(value1, - num + (1 - 2 * ((op - NJS_VMCODE_INCREMENT) >> 1))); - - njs_vmcode_operand(vm, vmcode->operand1, retval); - - if (op & 1) { - njs_set_number(retval, num); - - } else { - *retval = *value1; - } - - pc += sizeof(njs_vmcode_3addr_t); - goto next; - - case NJS_VMCODE_GLOBAL_GET: - 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); - } - - 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; - } - - 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; - } - - value2 = &primitive2; - } - - 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))); - - goto error; - } - - 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; - } - - if ((uint8_t) (op - NJS_VMCODE_GREATER) < 2) { - /* NJS_VMCODE_GREATER, NJS_VMCODE_LESS_OR_EQUAL */ - src = value1; - value1 = value2; - value2 = src; - } - - ret = njs_primitive_values_compare(vm, value1, value2); - - if (op < NJS_VMCODE_LESS_OR_EQUAL) { - ret = ret > 0; - - } else { - ret = ret == 0; - } - - njs_set_boolean(retval, ret); - - pc += sizeof(njs_vmcode_3addr_t); - goto next; - - case NJS_VMCODE_EQUAL: - case NJS_VMCODE_NOT_EQUAL: - ret = njs_values_equal(vm, value1, value2); - if (njs_slow_path(ret < 0)) { - goto error; - } - - 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; - } - - 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); - - switch (op) { - case NJS_VMCODE_SUBSTRACTION: - num -= njs_number(value2); - break; - - case NJS_VMCODE_MULTIPLICATION: - num *= njs_number(value2); - break; - - case NJS_VMCODE_EXPONENTIATION: - 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; - break; - - case NJS_VMCODE_DIVISION: - num /= njs_number(value2); - break; - - case NJS_VMCODE_REMAINDER: - num = fmod(num, njs_number(value2)); - break; - - case NJS_VMCODE_BITWISE_AND: - case NJS_VMCODE_BITWISE_OR: - case NJS_VMCODE_BITWISE_XOR: - i32 = njs_number_to_int32(njs_number(value2)); - - switch (op) { - case NJS_VMCODE_BITWISE_AND: - i32 &= njs_number_to_int32(num); - break; - - case NJS_VMCODE_BITWISE_OR: - i32 |= njs_number_to_int32(num); - break; - - case NJS_VMCODE_BITWISE_XOR: - i32 ^= njs_number_to_int32(num); - break; - } - - njs_set_int32(retval, i32); - goto next; - - default: - u32 = njs_number_to_uint32(njs_number(value2)) & 0x1f; - - switch (op) { - case NJS_VMCODE_LEFT_SHIFT: - case NJS_VMCODE_RIGHT_SHIFT: - i32 = njs_number_to_int32(num); - - if (op == NJS_VMCODE_LEFT_SHIFT) { - /* Shifting of negative numbers is undefined. */ - i32 = (uint32_t) i32 << u32; - } else { - i32 >>= u32; - } - - njs_set_int32(retval, i32); - break; - - default: /* NJS_VMCODE_UNSIGNED_RIGHT_SHIFT */ - njs_set_uint32(retval, - njs_number_to_uint32(num) >> u32); - } - - goto next; - } - - njs_set_number(retval, num); - goto next; - - case NJS_VMCODE_OBJECT_COPY: - ret = njs_vmcode_object_copy(vm, value1, value2); - break; - - case NJS_VMCODE_TEMPLATE_LITERAL: - ret = njs_vmcode_template_literal(vm, value1, value2); - break; - - case NJS_VMCODE_PROPERTY_IN: - ret = njs_vmcode_property_in(vm, value1, value2); - break; - - 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; - - ret = sizeof(njs_vmcode_3addr_t); - } - - break; - - case NJS_VMCODE_PROPERTY_FOREACH: - ret = njs_vmcode_property_foreach(vm, value1, value2, pc); - break; - - case NJS_VMCODE_STRICT_EQUAL: - case NJS_VMCODE_STRICT_NOT_EQUAL: - ret = njs_values_strict_equal(value1, value2); - - ret ^= op - NJS_VMCODE_STRICT_EQUAL; - - njs_vmcode_operand(vm, vmcode->operand1, retval); - njs_set_boolean(retval, ret); - - pc += sizeof(njs_vmcode_3addr_t); - goto next; - - 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); - - } else { - ret = njs_is_true(value1); - ret ^= op - NJS_VMCODE_TEST_IF_TRUE; - } - - if (ret) { - test_jump = (njs_vmcode_test_jump_t *) pc; - ret = test_jump->offset; - - } else { - ret = sizeof(njs_vmcode_3addr_t); - } - - njs_vmcode_operand(vm, vmcode->operand1, retval); - *retval = *value1; - - pc += ret; - goto next; - - 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; - } - - value1 = &numeric1; - } - - num = njs_number(value1); - njs_vmcode_operand(vm, vmcode->operand1, retval); - - switch (op) { - case NJS_VMCODE_UNARY_NEGATION: - num = -num; - - /* Fall through. */ - case NJS_VMCODE_UNARY_PLUS: - njs_set_number(retval, num); - break; - - case NJS_VMCODE_BITWISE_NOT: - njs_set_int32(retval, ~njs_number_to_uint32(num)); - } - - pc += sizeof(njs_vmcode_2addr_t); - goto next; - - case NJS_VMCODE_LOGICAL_NOT: - njs_vmcode_operand(vm, vmcode->operand1, retval); - njs_set_boolean(retval, !njs_is_true(value1)); - - pc += sizeof(njs_vmcode_2addr_t); - goto next; - - case NJS_VMCODE_OBJECT: - ret = njs_vmcode_object(vm); - break; - - case NJS_VMCODE_ARRAY: - ret = njs_vmcode_array(vm, pc); - break; - - case NJS_VMCODE_FUNCTION: - ret = njs_vmcode_function(vm, pc); - break; - - case NJS_VMCODE_REGEXP: - ret = njs_vmcode_regexp(vm, pc); - break; - - case NJS_VMCODE_INSTANCE_OF: - ret = njs_vmcode_instance_of(vm, value1, value2); - break; - - case NJS_VMCODE_TYPEOF: - ret = njs_vmcode_typeof(vm, value1, value2); - break; - - case NJS_VMCODE_VOID: - njs_set_undefined(&vm->retval); - - ret = sizeof(njs_vmcode_2addr_t); - break; - - case NJS_VMCODE_DELETE: - njs_release(vm, value1); - vm->retval = njs_value_true; - - ret = sizeof(njs_vmcode_2addr_t); - break; - - case NJS_VMCODE_DEBUGGER: - ret = njs_vmcode_debugger(vm); - break; - - default: - njs_internal_error(vm, "%d has retval", op); + 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(); _______________________________________________ nginx-devel mailing list -- nginx-devel@nginx.org To unsubscribe send an email to nginx-devel-le...@nginx.org