[njs] Computed goto support added to vmcode.
Vadim Zhestikov
v.zhestikov at f5.com
Tue Oct 25 13:53:32 UTC 2022
details: https://hg.nginx.org/njs/rev/86784a68e8c8
branches:
changeset: 1984:86784a68e8c8
user: Vadim Zhestikov <v.zhestikov at 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();
More information about the nginx-devel
mailing list