[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