From c8d15ddbf72b0fac8a89a28ec1a5d2da48930271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20G=C3=A1l?= Date: Wed, 15 Jul 2020 17:12:55 +0200 Subject: [PATCH] Date.protoype.toJSON should look for toISOString once (#3996) The toJSON method should be searched on the `this` object only once. In case of normal objects there were no problems however when a Proxy object is used as the `this` argument for the Date.prototype.toJSON method the Proxy's `get` method was invoked twice. JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.usz@partner.samsung.com --- .../ecma-builtin-date-prototype.c | 23 +++------- tests/jerry/date-tojson.js | 22 +++++++++ .../es.next/proxy-date-prototype-json.js | 45 +++++++++++++++++++ 3 files changed, 72 insertions(+), 18 deletions(-) create mode 100644 tests/jerry/date-tojson.js create mode 100644 tests/jerry/es.next/proxy-date-prototype-json.js diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c index 366043cbd..3300b909f 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c @@ -162,28 +162,15 @@ ecma_builtin_date_prototype_to_json (ecma_value_t this_arg) /**< this argument * return ECMA_VALUE_NULL; } } + else + { + ecma_free_value (tv); + } - ecma_value_t ret_value = ECMA_VALUE_ERROR; ecma_object_t *value_obj_p = ecma_get_object_from_value (obj); /* 4. */ - ecma_value_t to_iso = ecma_op_object_get_by_magic_id (value_obj_p, LIT_MAGIC_STRING_TO_ISO_STRING_UL); - - if (!ECMA_IS_VALUE_ERROR (to_iso)) - { - /* 5. */ - if (!ecma_op_is_callable (to_iso)) - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("'toISOString' is missing or not a function.")); - } - /* 6. */ - else - { - ret_value = ecma_op_invoke_by_magic_id (obj, LIT_MAGIC_STRING_TO_ISO_STRING_UL, NULL, 0); - } - - ecma_free_value (to_iso); - } + ecma_value_t ret_value = ecma_op_invoke_by_magic_id (obj, LIT_MAGIC_STRING_TO_ISO_STRING_UL, NULL, 0); ecma_deref_object (value_obj_p); diff --git a/tests/jerry/date-tojson.js b/tests/jerry/date-tojson.js new file mode 100644 index 000000000..5a80faca0 --- /dev/null +++ b/tests/jerry/date-tojson.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var obj = { + toISOString: function() { return "RESULT-ToISOString"; }, + valueOf: function() { return "RESULT-valueOf"; } +}; + +var result = Date.prototype.toJSON.call(obj); + +assert(result === "RESULT-ToISOString"); diff --git a/tests/jerry/es.next/proxy-date-prototype-json.js b/tests/jerry/es.next/proxy-date-prototype-json.js new file mode 100644 index 000000000..df88e5ded --- /dev/null +++ b/tests/jerry/es.next/proxy-date-prototype-json.js @@ -0,0 +1,45 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* Test the Date.prototype.toJSON method's internal operation order + * by creating a Proxy to catch the method invokations. + */ +var found = []; + +var target = { + toString: function() { return "TARGET_toString"; }, + toISOString: function() { return "TARGET_toISOString"; } +}; + +var prox = new Proxy(target, { + get: function(trg, key) { + found.push(key); + return trg[key]; + } +}); + +/* Date.prototype.toJSON -> ... -> .toISOString() */ +var json_result = Date.prototype.toJSON.call(prox); +assert(json_result === "TARGET_toISOString"); + +/* Data.prototype.toJSON -> toPrimitive -> Get -> [[Get]] + * The first element in the "found" properties should be the "@@toPrimitive" well-known Symbol. + */ +assert(found[0] === Symbol.toPrimitive); + +/* Date.prototype.toJSON -> Invoke -> GetMethod -> GetV -> [[Get]] + * All other elements are "methods" and there should be no duplicates. + */ +var methods = found.slice(1); +assert(methods.toString() === "valueOf,toString,toISOString");