[njs] Fixed addition operator applied to an object.
Igor Sysoev
igor at sysoev.ru
Tue Jul 24 17:09:09 UTC 2018
details: http://hg.nginx.org/njs/rev/766fcec15744
branches:
changeset: 571:766fcec15744
user: Igor Sysoev <igor at 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") },
More information about the nginx-devel
mailing list