[njs] Fixed Date() constructor with one argument.

Dmitry Volyntsev xeioex at nginx.com
Thu Apr 25 16:50:40 UTC 2019


details:   https://hg.nginx.org/njs/rev/43dc900bc914
branches:  
changeset: 930:43dc900bc914
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu Apr 25 19:50:20 2019 +0300
description:
Fixed Date() constructor with one argument.

This closes #144 issue on Github.

diffstat:

 njs/njs_date.c           |  64 +++++++++++++++++++++++++++++++----------------
 njs/njs_number.c         |   2 +-
 njs/njs_number.h         |   1 +
 njs/njs_vm.c             |  53 +++++++++++++++++++++++++++++++++------
 njs/njs_vm.h             |   1 +
 njs/test/njs_unit_test.c |  36 +++++++++++++++++++++++++++
 6 files changed, 125 insertions(+), 32 deletions(-)

diffs (274 lines):

diff -r 65d6076eb349 -r 43dc900bc914 njs/njs_date.c
--- a/njs/njs_date.c	Thu Apr 25 19:33:35 2019 +0300
+++ b/njs/njs_date.c	Thu Apr 25 19:50:20 2019 +0300
@@ -61,6 +61,17 @@ njs_gettime(void)
 }
 
 
+static nxt_noinline double
+njs_timeclip(double time)
+{
+    if (isinf(time) || isnan(time) || fabs(time) > 8.64e15) {
+        return NAN;
+    }
+
+    return njs_number_to_int64(time);
+}
+
+
 njs_ret_t
 njs_date_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
@@ -76,8 +87,22 @@ njs_date_constructor(njs_vm_t *vm, njs_v
         if (nargs == 1) {
             time = njs_gettime();
 
-        } else if (nargs == 2 && njs_is_string(&args[1])) {
-            time = njs_date_string_parse(&args[1]);
+        } else if (nargs == 2) {
+            if (njs_is_object(&args[1])) {
+                if (!njs_is_date(&args[1])) {
+                    njs_vm_trap_value(vm, &args[1]);
+
+                    return njs_trap(vm, NJS_TRAP_PRIMITIVE_ARG);
+                }
+
+                time = args[1].data.u.date->time;
+
+            } else if (njs_is_string(&args[1])) {
+                time = njs_date_string_parse(&args[1]);
+
+            } else {
+                time = args[1].data.u.number;
+            }
 
         } else {
             nxt_memzero(values, 8 * sizeof(int64_t));
@@ -103,25 +128,20 @@ njs_date_constructor(njs_vm_t *vm, njs_v
                 values[i] = num;
             }
 
-            if (nargs > 2) {
-                /* Year. */
-                if (values[1] > 99) {
-                    values[1] -= 1900;
-                }
-
-                tm.tm_year = values[1];
-                tm.tm_mon = values[2];
-                tm.tm_mday = values[3];
-                tm.tm_hour = values[4];
-                tm.tm_min = values[5];
-                tm.tm_sec = values[6];
-                tm.tm_isdst = -1;
-
-                time = (int64_t) mktime(&tm) * 1000 + values[7];
-
-            } else {
-                time = values[1];
+            /* Year. */
+            if (values[1] > 99) {
+                values[1] -= 1900;
             }
+
+            tm.tm_year = values[1];
+            tm.tm_mon = values[2];
+            tm.tm_mday = values[3];
+            tm.tm_hour = values[4];
+            tm.tm_min = values[5];
+            tm.tm_sec = values[6];
+            tm.tm_isdst = -1;
+
+            time = (int64_t) mktime(&tm) * 1000 + values[7];
         }
 
     done:
@@ -139,7 +159,7 @@ njs_date_constructor(njs_vm_t *vm, njs_v
         date->object.extensible = 1;
         date->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_DATE].object;
 
-        date->time = time;
+        date->time = njs_timeclip(time);
 
         vm->retval.data.u.date = date;
         vm->retval.type = NJS_DATE;
@@ -1048,7 +1068,7 @@ njs_date_to_string(njs_vm_t *vm, njs_val
         return njs_string_new(vm, retval, buf, p - buf, p - buf);
     }
 
-    vm->retval = njs_string_invalid_date;
+    *retval = njs_string_invalid_date;
 
     return NXT_OK;
 }
diff -r 65d6076eb349 -r 43dc900bc914 njs/njs_number.c
--- a/njs/njs_number.c	Thu Apr 25 19:33:35 2019 +0300
+++ b/njs/njs_number.c	Thu Apr 25 19:50:20 2019 +0300
@@ -804,7 +804,7 @@ njs_number_parse_float(njs_vm_t *vm, njs
 }
 
 
-nxt_inline int64_t
+int64_t
 njs_number_to_int64(double num)
 {
 #if (NXT_NAN_TO_UINT_CONVERSION != 0)
diff -r 65d6076eb349 -r 43dc900bc914 njs/njs_number.h
--- a/njs/njs_number.h	Thu Apr 25 19:33:35 2019 +0300
+++ b/njs/njs_number.h	Thu Apr 25 19:50:20 2019 +0300
@@ -35,6 +35,7 @@ njs_ret_t njs_number_parse_int(njs_vm_t 
     nxt_uint_t nargs, njs_index_t unused);
 njs_ret_t njs_number_parse_float(njs_vm_t *vm, njs_value_t *args,
     nxt_uint_t nargs, njs_index_t unused);
+int64_t njs_number_to_int64(double num);
 nxt_noinline int32_t njs_number_to_integer(double num);
 nxt_noinline int32_t njs_number_to_int32(double num);
 nxt_noinline uint32_t njs_number_to_uint32(double num);
diff -r 65d6076eb349 -r 43dc900bc914 njs/njs_vm.c
--- a/njs/njs_vm.c	Thu Apr 25 19:33:35 2019 +0300
+++ b/njs/njs_vm.c	Thu Apr 25 19:50:20 2019 +0300
@@ -50,6 +50,8 @@ static njs_ret_t njs_vmcode_number_argum
     njs_value_t *inlvd2);
 static njs_ret_t njs_vmcode_string_argument(njs_vm_t *vm, njs_value_t *invld1,
     njs_value_t *inlvd2);
+static njs_ret_t njs_vmcode_primitive_argument(njs_vm_t *vm,
+    njs_value_t *invld1, njs_value_t *inlvd2);
 static njs_ret_t njs_primitive_value(njs_vm_t *vm, njs_value_t *value,
     nxt_uint_t hint);
 static njs_ret_t njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1,
@@ -199,6 +201,7 @@ start:
 
         case NJS_TRAP_NUMBER_ARG:
         case NJS_TRAP_STRING_ARG:
+        case NJS_TRAP_PRIMITIVE_ARG:
 
             njs_vm_trap_argument(vm, trap);
 
@@ -2608,16 +2611,24 @@ static const njs_vmcode_1addr_t  njs_tra
 };
 
 
+static const njs_vmcode_1addr_t  njs_trap_primitive_argument = {
+    .code = { .operation = njs_vmcode_primitive_argument,
+              .operands =  NJS_VMCODE_NO_OPERAND,
+              .retval = NJS_VMCODE_NO_RETVAL }
+};
+
+
 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_PROPERTY   */  { .code = &njs_trap_property[0]     },
-    /* NJS_TRAP_NUMBER_ARG */  { .code = &njs_trap_number_argument },
-    /* NJS_TRAP_STRING_ARG */  { .code = &njs_trap_string_argument },
+    /* 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_PROPERTY   */     { .code = &njs_trap_property[0]     },
+    /* NJS_TRAP_NUMBER_ARG */     { .code = &njs_trap_number_argument },
+    /* NJS_TRAP_STRING_ARG */     { .code = &njs_trap_string_argument },
+    /* NJS_TRAP_PRIMITIVE_ARG */  { .code = &njs_trap_primitive_argument },
 };
 
 
@@ -2831,6 +2842,30 @@ njs_vmcode_string_argument(njs_vm_t *vm,
 
 
 static njs_ret_t
+njs_vmcode_primitive_argument(njs_vm_t *vm, njs_value_t *invld1,
+    njs_value_t *inlvd2)
+{
+    njs_ret_t    ret;
+    njs_value_t  *value;
+
+    value = &vm->top_frame->trap_values[0];
+
+    ret = njs_primitive_value(vm, value, 0);
+
+    if (nxt_fast_path(ret > 0)) {
+        *vm->top_frame->trap_values[1].data.u.value = *value;
+
+        vm->current = vm->top_frame->trap_restart;
+        vm->top_frame->trap_restart = NULL;
+
+        return 0;
+    }
+
+    return ret;
+}
+
+
+static njs_ret_t
 njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
 {
     u_char                *restart;
diff -r 65d6076eb349 -r 43dc900bc914 njs/njs_vm.h
--- a/njs/njs_vm.h	Thu Apr 25 19:33:35 2019 +0300
+++ b/njs/njs_vm.h	Thu Apr 25 19:50:20 2019 +0300
@@ -47,6 +47,7 @@ typedef enum {
     NJS_TRAP_PROPERTY,
     NJS_TRAP_NUMBER_ARG,
     NJS_TRAP_STRING_ARG,
+    NJS_TRAP_PRIMITIVE_ARG,
 } njs_trap_t;
 
 
diff -r 65d6076eb349 -r 43dc900bc914 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Thu Apr 25 19:33:35 2019 +0300
+++ b/njs/test/njs_unit_test.c	Thu Apr 25 19:50:20 2019 +0300
@@ -9563,12 +9563,48 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Object.isExtensible(Object.freeze([]))"),
       nxt_string("false") },
 
+    { nxt_string("new Date(undefined)"),
+      nxt_string("Invalid Date") },
+
+    { nxt_string("new Date(Infinity)"),
+      nxt_string("Invalid Date") },
+
+    { nxt_string("new Date(NaN)"),
+      nxt_string("Invalid Date") },
+
+    { nxt_string("new Date(8.65e15)"),
+      nxt_string("Invalid Date") },
+
+    { nxt_string("new Date(0e0.o0)"),
+      nxt_string("Invalid Date") },
+
+    { nxt_string("(new Date(8.639e15)).getTime()"),
+      nxt_string("8639000000000000") },
+
+    { nxt_string("new Date(8.641e15)"),
+      nxt_string("Invalid Date") },
+
+    { nxt_string("(new Date(null)).getTime()"),
+      nxt_string("0") },
+
+    { nxt_string("(new Date(86400)).getTime()"),
+      nxt_string("86400") },
+
     { 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 00:00:00 GMT+0000") },
 
+    { nxt_string("var d = new Date({valueOf:()=>86400000}); d = d + ''; d.slice(0, 33)"),
+      nxt_string("Fri Jan 02 1970 00:00:00 GMT+0000") },
+
+    { nxt_string("(new Date({toString:()=>'2011'})).getTime()"),
+      nxt_string("1293840000000") },
+
+    { nxt_string("(new Date({valueOf: ()=>86400, toString:()=>'2011'})).getTime()"),
+      nxt_string("86400") },
+
     { nxt_string("var d = new Date(1308895200000); d.getTime()"),
       nxt_string("1308895200000") },
 


More information about the nginx-devel mailing list