[njs] Fixed Array.prototype.toString() and Date.prototype.toJSON().

Dmitry Volyntsev xeioex at nginx.com
Fri May 24 15:59:49 UTC 2019


details:   https://hg.nginx.org/njs/rev/ff51b3e9ea05
branches:  
changeset: 984:ff51b3e9ea05
user:      hongzhidao <hongzhidao at gmail.com>
date:      Wed May 22 07:54:58 2019 +0800
description:
Fixed Array.prototype.toString() and Date.prototype.toJSON().

This closes #163, #164, #166 issues on Github.

diffstat:

 njs/njs_array.c          |  28 ++--------------------------
 njs/njs_date.c           |  27 ++-------------------------
 njs/njs_function.h       |  30 ++++++++++++++++++++++++++++++
 njs/test/njs_unit_test.c |   6 ++++++
 4 files changed, 40 insertions(+), 51 deletions(-)

diffs (187 lines):

diff -r 5906cf108796 -r ff51b3e9ea05 njs/njs_array.c
--- a/njs/njs_array.c	Thu May 23 16:21:55 2019 +0300
+++ b/njs/njs_array.c	Wed May 22 07:54:58 2019 +0800
@@ -85,8 +85,6 @@ static njs_ret_t njs_array_prototype_sli
     njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
 static njs_ret_t njs_array_prototype_slice_copy(njs_vm_t *vm,
     njs_value_t *this, int64_t start, int64_t length);
-static njs_ret_t njs_array_prototype_to_string_continuation(njs_vm_t *vm,
-    njs_value_t *args, nxt_uint_t nargs, njs_index_t retval);
 static njs_ret_t njs_array_prototype_join_continuation(njs_vm_t *vm,
     njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
 static njs_value_t *njs_array_copy(njs_value_t *dst, njs_value_t *src);
@@ -935,24 +933,13 @@ njs_array_prototype_reverse(njs_vm_t *vm
 }
 
 
-/*
- * ECMAScript 5.1: try first to use object method "join", then
- * use the standard built-in method Object.prototype.toString().
- * Array.toString() must be a continuation otherwise it may
- * endlessly call Array.join().
- */
-
 static njs_ret_t
 njs_array_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t retval)
 {
     njs_object_prop_t   *prop;
-    njs_continuation_t  *cont;
     nxt_lvlhsh_query_t  lhq;
 
-    cont = njs_vm_continuation(vm);
-    cont->function = njs_array_prototype_to_string_continuation;
-
     if (njs_is_object(&args[0])) {
         lhq.key_hash = NJS_JOIN_HASH;
         lhq.key = nxt_string_value("join");
@@ -960,8 +947,8 @@ njs_array_prototype_to_string(njs_vm_t *
         prop = njs_object_property(vm, args[0].data.u.object, &lhq);
 
         if (nxt_fast_path(prop != NULL && njs_is_function(&prop->value))) {
-            return njs_function_apply(vm, prop->value.data.u.function,
-                                      args, nargs, retval);
+            return njs_function_replace(vm, prop->value.data.u.function,
+                                        args, nargs, retval);
         }
     }
 
@@ -970,17 +957,6 @@ njs_array_prototype_to_string(njs_vm_t *
 
 
 static njs_ret_t
-njs_array_prototype_to_string_continuation(njs_vm_t *vm, njs_value_t *args,
-    nxt_uint_t nargs, njs_index_t retval)
-{
-    /* Skip retval update. */
-    vm->top_frame->skip = 1;
-
-    return NXT_OK;
-}
-
-
-static njs_ret_t
 njs_array_prototype_join(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
 {
diff -r 5906cf108796 -r ff51b3e9ea05 njs/njs_date.c
--- a/njs/njs_date.c	Thu May 23 16:21:55 2019 +0300
+++ b/njs/njs_date.c	Wed May 22 07:54:58 2019 +0800
@@ -43,8 +43,6 @@ static nxt_noinline njs_ret_t njs_date_s
     double time);
 static nxt_noinline double njs_date_time(struct tm *tm, int64_t ms);
 static double njs_date_utc_time(struct tm *tm, double time);
-static njs_ret_t njs_date_prototype_to_json_continuation(njs_vm_t *vm,
-    njs_value_t *args, nxt_uint_t nargs, njs_index_t retval);
 
 
 static const njs_value_t  njs_string_invalid_date = njs_string("Invalid Date");
@@ -1895,23 +1893,13 @@ njs_date_utc_time(struct tm *tm, double 
 }
 
 
-/*
- * ECMAScript 5.1: call object method "toISOString".
- * Date.toJSON() must be a continuation otherwise it may endlessly
- * call Date.toISOString().
- */
-
 static njs_ret_t
 njs_date_prototype_to_json(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t retval)
 {
     njs_object_prop_t   *prop;
-    njs_continuation_t  *cont;
     nxt_lvlhsh_query_t  lhq;
 
-    cont = njs_vm_continuation(vm);
-    cont->function = njs_date_prototype_to_json_continuation;
-
     if (njs_is_object(&args[0])) {
         lhq.key_hash = NJS_TO_ISO_STRING_HASH;
         lhq.key = nxt_string_value("toISOString");
@@ -1919,8 +1907,8 @@ njs_date_prototype_to_json(njs_vm_t *vm,
         prop = njs_object_property(vm, args[0].data.u.object, &lhq);
 
         if (nxt_fast_path(prop != NULL && njs_is_function(&prop->value))) {
-            return njs_function_apply(vm, prop->value.data.u.function,
-                                      args, nargs, retval);
+            return njs_function_replace(vm, prop->value.data.u.function,
+                                        args, nargs, retval);
         }
     }
 
@@ -1930,17 +1918,6 @@ njs_date_prototype_to_json(njs_vm_t *vm,
 }
 
 
-static njs_ret_t
-njs_date_prototype_to_json_continuation(njs_vm_t *vm, njs_value_t *args,
-    nxt_uint_t nargs, njs_index_t retval)
-{
-    /* Skip retval update. */
-    vm->top_frame->skip = 1;
-
-    return NXT_OK;
-}
-
-
 static const njs_object_prop_t  njs_date_prototype_properties[] =
 {
     {
diff -r 5906cf108796 -r ff51b3e9ea05 njs/njs_function.h
--- a/njs/njs_function.h	Thu May 23 16:21:55 2019 +0300
+++ b/njs/njs_function.h	Wed May 22 07:54:58 2019 +0800
@@ -200,6 +200,36 @@ njs_function_apply(njs_vm_t *vm, njs_fun
 }
 
 
+/*
+ * Replaces the current function with a new one.
+ * Can only be used for continuation functions
+ * (data.u.function.continuation_size > 0).
+ */
+nxt_inline njs_ret_t
+njs_function_replace(njs_vm_t *vm, njs_function_t *function,
+    const njs_value_t *args, nxt_uint_t nargs, njs_index_t retval)
+{
+    nxt_int_t  ret;
+
+    ret = njs_function_apply(vm, function, args, nargs, retval);
+    if (nxt_slow_path(ret == NXT_ERROR)) {
+        return ret;
+    }
+
+    /*
+     * 1) njs_function_apply() allocs a new function frame,
+     *    in order to preserve the retval of a new function and ignore
+     *    retval of the current function during stack unwinding
+     *    skip flag is needed.
+     * 2) it is also needed for correct callee arguments update in
+     *    njs_function_native_call() see "Object((new Date(0)).toJSON())".
+     */
+    vm->top_frame->previous->skip = 1;
+
+    return NJS_APPLIED;
+}
+
+
 nxt_inline njs_native_frame_t *
 njs_function_previous_frame(njs_native_frame_t *frame)
 {
diff -r 5906cf108796 -r ff51b3e9ea05 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Thu May 23 16:21:55 2019 +0300
+++ b/njs/test/njs_unit_test.c	Wed May 22 07:54:58 2019 +0800
@@ -6085,6 +6085,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("function f(a,b) { }; var ff = f.bind(f, 1); ff.length"),
       nxt_string("1") },
 
+    { nxt_string("Object((new Date(0)).toJSON())+0"),
+      nxt_string("1970-01-01T00:00:00.000Z0") },
+
+    { nxt_string("Object((new Array(0)).toString())+0"),
+      nxt_string("0") },
+
     { nxt_string("JSON.parse.length"),
       nxt_string("2") },
 


More information about the nginx-devel mailing list