details: http://hg.nginx.org/njs/rev/766fcec15744 branches: changeset: 571:766fcec15744 user: Igor Sysoev <i...@sysoev.ru> date: Tue Jul 24 19:50:02 2018 +0300 description: Fixed addition operator applied to an object.
This fixes #36 issue on Github. diffstat: njs/njs_vm.c | 190 +++++++++++++++++++++++++++++++++++++--------- njs/njs_vm.h | 3 +- njs/test/njs_unit_test.c | 6 + 3 files changed, 160 insertions(+), 39 deletions(-) diffs (314 lines): diff -r 69300ba58603 -r 766fcec15744 njs/njs_vm.c --- a/njs/njs_vm.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_vm.c Tue Jul 24 19:50:02 2018 +0300 @@ -23,6 +23,8 @@ struct njs_property_next_s { * and should fit in CPU L1 instruction cache. */ +static nxt_noinline njs_ret_t njs_string_concat(njs_vm_t *vm, + njs_value_t *val1, njs_value_t *val2); static njs_ret_t njs_method_private_copy(njs_vm_t *vm, njs_property_query_t *pq); static nxt_noinline njs_ret_t njs_values_equal(njs_vm_t *vm, @@ -48,6 +50,10 @@ static njs_ret_t njs_vmcode_number_primi njs_value_t *narg); static njs_ret_t njs_vmcode_string_primitive(njs_vm_t *vm, njs_value_t *invld, njs_value_t *narg); +static njs_ret_t njs_vmcode_addition_primitive(njs_vm_t *vm, njs_value_t *invld, + njs_value_t *narg); +static njs_ret_t njs_vmcode_comparison_primitive(njs_vm_t *vm, + njs_value_t *invld, njs_value_t *narg); static njs_ret_t njs_vmcode_number_argument(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *inlvd2); static njs_ret_t njs_vmcode_string_argument(njs_vm_t *vm, njs_value_t *invld1, @@ -181,7 +187,8 @@ start: /* Fall through. */ case NJS_TRAP_NUMBERS: - case NJS_TRAP_STRINGS: + case NJS_TRAP_ADDITION: + case NJS_TRAP_COMPARISON: case NJS_TRAP_INCDEC: case NJS_TRAP_PROPERTY: @@ -1301,10 +1308,9 @@ njs_vmcode_unary_negation(njs_vm_t *vm, njs_ret_t njs_vmcode_addition(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2) { - double num; - u_char *start; - size_t size, length; - njs_string_prop_t string1, string2; + double num; + njs_ret_t ret; + njs_value_t *s1, *s2, *src, dst; if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) { @@ -1315,34 +1321,70 @@ njs_vmcode_addition(njs_vm_t *vm, njs_va } if (nxt_fast_path(njs_is_string(val1) && njs_is_string(val2))) { - - (void) njs_string_prop(&string1, val1); - (void) njs_string_prop(&string2, val2); - - if ((string1.length != 0 || string1.size == 0) - && (string2.length != 0 || string2.size == 0)) - { - length = string1.length + string2.length; + return njs_string_concat(vm, val1, val2); + } + + if (nxt_fast_path(njs_is_primitive(val1) && njs_is_primitive(val2))) { + + if (njs_is_string(val1)) { + s1 = val1; + s2 = &dst; + src = val2; } else { - length = 0; + s1 = &dst; + s2 = val2; + src = val1; + } + + ret = njs_primitive_value_to_string(vm, &dst, src); + + if (nxt_fast_path(ret == NXT_OK)) { + return njs_string_concat(vm, s1, s2); } - size = string1.size + string2.size; - - start = njs_string_alloc(vm, &vm->retval, size, length); - - if (nxt_slow_path(start == NULL)) { - return NXT_ERROR; - } - - (void) memcpy(start, string1.start, string1.size); - (void) memcpy(start + string1.size, string2.start, string2.size); - - return sizeof(njs_vmcode_3addr_t); + return ret; } - return njs_trap(vm, NJS_TRAP_STRINGS); + return njs_trap(vm, NJS_TRAP_ADDITION); +} + + +static nxt_noinline njs_ret_t +njs_string_concat(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2) +{ + u_char *start; + size_t size, length; + njs_string_prop_t string1, string2; + + (void) njs_string_prop(&string1, val1); + (void) njs_string_prop(&string2, val2); + + /* + * A result of concatenation of Byte and ASCII or UTF-8 strings + * is a Byte string. + */ + if ((string1.length != 0 || string1.size == 0) + && (string2.length != 0 || string2.size == 0)) + { + length = string1.length + string2.length; + + } else { + length = 0; + } + + size = string1.size + string2.size; + + start = njs_string_alloc(vm, &vm->retval, size, length); + + if (nxt_slow_path(start == NULL)) { + return NXT_ERROR; + } + + (void) memcpy(start, string1.start, string1.size); + (void) memcpy(start + string1.size, string2.start, string2.size); + + return sizeof(njs_vmcode_3addr_t); } @@ -1778,7 +1820,7 @@ njs_values_compare(njs_vm_t *vm, const n return (njs_string_cmp(val1, val2) < 0) ? 1 : 0; } - return njs_trap(vm, NJS_TRAP_STRINGS); + return njs_trap(vm, NJS_TRAP_COMPARISON); } @@ -2781,15 +2823,11 @@ njs_vmcode_finally(njs_vm_t *vm, njs_val } -static const njs_vmcode_1addr_t njs_trap_strings[] = { - { .code = { .operation = njs_vmcode_string_primitive, +static const njs_vmcode_1addr_t njs_trap_number[] = { + { .code = { .operation = njs_vmcode_number_primitive, .operands = NJS_VMCODE_1OPERAND, .retval = NJS_VMCODE_NO_RETVAL }, .index = 0 }, - { .code = { .operation = njs_vmcode_string_primitive, - .operands = NJS_VMCODE_1OPERAND, - .retval = NJS_VMCODE_NO_RETVAL }, - .index = 1 }, { .code = { .operation = njs_vmcode_restart, .operands = NJS_VMCODE_NO_OPERAND, .retval = NJS_VMCODE_NO_RETVAL } }, @@ -2811,11 +2849,41 @@ static const njs_vmcode_1addr_t njs_tra }; -static const njs_vmcode_1addr_t njs_trap_number[] = { - { .code = { .operation = njs_vmcode_number_primitive, +static const njs_vmcode_1addr_t njs_trap_addition[] = { + { .code = { .operation = njs_vmcode_addition_primitive, .operands = NJS_VMCODE_1OPERAND, .retval = NJS_VMCODE_NO_RETVAL }, .index = 0 }, + { .code = { .operation = njs_vmcode_addition_primitive, + .operands = NJS_VMCODE_1OPERAND, + .retval = NJS_VMCODE_NO_RETVAL }, + .index = 1 }, + { .code = { .operation = njs_vmcode_restart, + .operands = NJS_VMCODE_NO_OPERAND, + .retval = NJS_VMCODE_NO_RETVAL } }, +}; + + +static const njs_vmcode_1addr_t njs_trap_comparison[] = { + { .code = { .operation = njs_vmcode_comparison_primitive, + .operands = NJS_VMCODE_1OPERAND, + .retval = NJS_VMCODE_NO_RETVAL }, + .index = 0 }, + { .code = { .operation = njs_vmcode_comparison_primitive, + .operands = NJS_VMCODE_1OPERAND, + .retval = NJS_VMCODE_NO_RETVAL }, + .index = 1 }, + { .code = { .operation = njs_vmcode_restart, + .operands = NJS_VMCODE_NO_OPERAND, + .retval = NJS_VMCODE_NO_RETVAL } }, +}; + + +static const njs_vmcode_1addr_t njs_trap_property[] = { + { .code = { .operation = njs_vmcode_string_primitive, + .operands = NJS_VMCODE_1OPERAND, + .retval = NJS_VMCODE_NO_RETVAL }, + .index = 1 }, { .code = { .operation = njs_vmcode_restart, .operands = NJS_VMCODE_NO_OPERAND, .retval = NJS_VMCODE_NO_RETVAL } }, @@ -2839,10 +2907,11 @@ static const njs_vmcode_1addr_t njs_tra static const njs_vm_trap_t njs_vm_traps[] = { /* NJS_TRAP_NUMBER */ { .code = &njs_trap_number[0] }, /* NJS_TRAP_NUMBERS */ { .code = &njs_trap_numbers[0] }, + /* NJS_TRAP_ADDITION */ { .code = &njs_trap_addition[0] }, + /* NJS_TRAP_COMPARISON */ { .code = &njs_trap_comparison[0] }, /* NJS_TRAP_INCDEC */ { .code = &njs_trap_numbers[1], .reference = 1 }, - /* NJS_TRAP_STRINGS */ { .code = &njs_trap_strings[0] }, - /* NJS_TRAP_PROPERTY */ { .code = &njs_trap_strings[1] }, + /* NJS_TRAP_PROPERTY */ { .code = &njs_trap_property[0] }, /* NJS_TRAP_NUMBER_ARG */ { .code = &njs_trap_number_argument }, /* NJS_TRAP_STRING_ARG */ { .code = &njs_trap_string_argument }, }; @@ -2951,6 +3020,51 @@ njs_vmcode_string_primitive(njs_vm_t *vm static njs_ret_t +njs_vmcode_addition_primitive(njs_vm_t *vm, njs_value_t *invld, + njs_value_t *narg) +{ + njs_ret_t ret; + nxt_uint_t hint; + njs_value_t *value; + + value = &vm->top_frame->trap_values[(uintptr_t) narg]; + + /* + * ECMAScript 5.1: + * Date should return String, other types sould return Number. + */ + hint = njs_is_date(value); + + ret = njs_primitive_value(vm, value, hint); + + if (nxt_fast_path(ret > 0)) { + return sizeof(njs_vmcode_1addr_t); + } + + return ret; +} + + +static njs_ret_t +njs_vmcode_comparison_primitive(njs_vm_t *vm, njs_value_t *invld, + njs_value_t *narg) +{ + njs_ret_t ret; + njs_value_t *value; + + value = &vm->top_frame->trap_values[(uintptr_t) narg]; + + ret = njs_primitive_value(vm, value, 0); + + if (nxt_fast_path(ret > 0)) { + return sizeof(njs_vmcode_1addr_t); + } + + return ret; +} + + +static njs_ret_t njs_vmcode_number_argument(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *inlvd2) { diff -r 69300ba58603 -r 766fcec15744 njs/njs_vm.h --- a/njs/njs_vm.h Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_vm.h Tue Jul 24 19:50:02 2018 +0300 @@ -41,8 +41,9 @@ typedef enum { NJS_TRAP_NUMBER = 0, NJS_TRAP_NUMBERS, + NJS_TRAP_ADDITION, + NJS_TRAP_COMPARISON, NJS_TRAP_INCDEC, - NJS_TRAP_STRINGS, NJS_TRAP_PROPERTY, NJS_TRAP_NUMBER_ARG, NJS_TRAP_STRING_ARG, diff -r 69300ba58603 -r 766fcec15744 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Jul 24 19:50:02 2018 +0300 @@ -386,6 +386,9 @@ static njs_unit_test_t njs_test[] = " toString: function() { return '1' } }; +a"), nxt_string("1") }, + { nxt_string("var a = { valueOf: function() { return 1 } }; ''+a"), + nxt_string("1") }, + { nxt_string("var a = { valueOf: function() { return [] }," " toString: function() { return '1' } }; +a"), nxt_string("1") }, @@ -7159,6 +7162,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var d = new Date(''); d +' '+ d.getTime()"), nxt_string("Invalid Date NaN") }, + { nxt_string("var d = new Date(1); d = d + ''; d.slice(0, 33)"), + nxt_string("Thu Jan 01 1970 12:45:00 GMT+1245") }, + { nxt_string("var d = new Date(1308895200000); d.getTime()"), nxt_string("1308895200000") }, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel