]> git.kaiwu.me - njs.git/commitdiff
Fixed Array.prototype.toString() and Date.prototype.toJSON().
authorhongzhidao <hongzhidao@gmail.com>
Tue, 21 May 2019 23:54:58 +0000 (07:54 +0800)
committerhongzhidao <hongzhidao@gmail.com>
Tue, 21 May 2019 23:54:58 +0000 (07:54 +0800)
This closes #163, #164, #166 issues on Github.

njs/njs_array.c
njs/njs_date.c
njs/njs_function.h
njs/test/njs_unit_test.c

index 2f13437bc0f3ee23a79620b107ba2a06a16f38f8..c62ae18d5d1c291e9133ec588b576718e6d64024 100644 (file)
@@ -85,8 +85,6 @@ static njs_ret_t njs_array_prototype_slice_continuation(njs_vm_t *vm,
     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, njs_value_t *args, nxt_uint_t nargs,
 }
 
 
-/*
- * 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 *vm, njs_value_t *args, nxt_uint_t nargs,
         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);
         }
     }
 
@@ -969,17 +956,6 @@ njs_array_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
 }
 
 
-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)
index e1ca585c4ca1ab85059e94fca2f44d66365ef4f7..08bb30b4d6f0bcc5b68d1a00455c228edb41d270 100644 (file)
@@ -43,8 +43,6 @@ static nxt_noinline njs_ret_t njs_date_string(njs_vm_t *vm, const char *fmt,
     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 time)
 }
 
 
-/*
- * 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, njs_value_t *args, nxt_uint_t nargs,
         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, njs_value_t *args, nxt_uint_t nargs,
 }
 
 
-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[] =
 {
     {
index 149e0ae47b279005e817fd93eea1b694dbf76aed..7a9cb43a4cfaea35aefd3a5f990b3216b82cad3b 100644 (file)
@@ -200,6 +200,36 @@ njs_function_apply(njs_vm_t *vm, njs_function_t *function,
 }
 
 
+/*
+ * 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)
 {
index 1a98ae6fceedd107eead8ed8e351ac2138893e8b..c840376b12e5e5de294f6c91af9e43fc756fbcbf 100644 (file)
@@ -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") },