From: hongzhidao Date: Tue, 21 May 2019 23:54:58 +0000 (+0800) Subject: Fixed Array.prototype.toString() and Date.prototype.toJSON(). X-Git-Tag: 0.3.3~32 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=1f4c515f74a71df9d0a40bb786cce7467f0a904e;p=njs.git Fixed Array.prototype.toString() and Date.prototype.toJSON(). This closes #163, #164, #166 issues on Github. --- diff --git a/njs/njs_array.c b/njs/njs_array.c index 2f13437b..c62ae18d 100644 --- a/njs/njs_array.c +++ b/njs/njs_array.c @@ -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) diff --git a/njs/njs_date.c b/njs/njs_date.c index e1ca585c..08bb30b4 100644 --- a/njs/njs_date.c +++ b/njs/njs_date.c @@ -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[] = { { diff --git a/njs/njs_function.h b/njs/njs_function.h index 149e0ae4..7a9cb43a 100644 --- a/njs/njs_function.h +++ b/njs/njs_function.h @@ -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) { diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 1a98ae6f..c840376b 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -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") },