From 2ac4c4a4c52f81a5c9a3eb33215f325b778f8b94 Mon Sep 17 00:00:00 2001 From: Peter Gal Date: Tue, 26 May 2020 10:52:14 +0200 Subject: [PATCH] Improve property key query for Proxy objects Property key query for Proxy objects always returned all keys even if no symbols were requested symbols were present in the resulting array. JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.usz@partner.samsung.com --- jerry-core/ecma/operations/ecma-objects.c | 32 ++++++++++++++++++- tests/jerry/es2015/proxy_own_keys.js | 29 +++++++++++------ .../es2015/regression-test-issue-3787.js | 22 +++++++++++++ 3 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 tests/jerry/es2015/regression-test-issue-3787.js diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 76daa04348..cc1b0e3b5c 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -2041,7 +2041,37 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ #if ENABLED (JERRY_ES2015_BUILTIN_PROXY) if (ECMA_OBJECT_IS_PROXY (obj_p)) { - return ecma_proxy_object_own_property_keys (obj_p); + /* Integrated a part of ECMA 262 v6 7.3.21 EnumerableOwnNames operation. */ + ecma_collection_t *proxy_keys = ecma_proxy_object_own_property_keys (obj_p); + if (JERRY_UNLIKELY (proxy_keys == NULL)) + { + return proxy_keys; + } + ecma_collection_t *return_keys = ecma_new_collection (); + + /* Move valid elements to the output collection */ + for (uint32_t i = 0; i < proxy_keys->item_count; i++) + { + ecma_value_t entry = proxy_keys->buffer_p[i]; + ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (entry); + bool prop_is_symbol = ecma_prop_name_is_symbol (prop_name_p); + + if (prop_is_symbol && ((opts & (ECMA_LIST_SYMBOLS | ECMA_LIST_SYMBOLS_ONLY)) != 0)) + { + ecma_collection_push_back (return_keys, entry); + } + else if (!prop_is_symbol && (opts & ECMA_LIST_SYMBOLS_ONLY) == 0) + { + ecma_collection_push_back (return_keys, entry); + } + else + { + ecma_free_value (entry); + } + } + + ecma_collection_destroy (proxy_keys); + return return_keys; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ diff --git a/tests/jerry/es2015/proxy_own_keys.js b/tests/jerry/es2015/proxy_own_keys.js index 5cc79be171..9c2f038043 100644 --- a/tests/jerry/es2015/proxy_own_keys.js +++ b/tests/jerry/es2015/proxy_own_keys.js @@ -16,6 +16,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +function array_check(result_array, expected_array) { + assert(result_array instanceof Array); + assert(result_array.length === expected_array.length); + for (var idx = 0; idx < expected_array.length; idx++) { + assert(result_array[idx] === expected_array[idx]); + } +} + var target = {}; var handler = { ownKeys (target) { throw 42; @@ -56,26 +64,29 @@ try { } // test basic functionality +var symA = Symbol("smA"); +var symB = Symbol("smB"); var target = { prop1: "prop1", prop2: "prop2"}; +target[symB] = "s3"; var handler = { ownKeys: function(target) { - return ["foo", "bar"]; + return ["foo", "bar", symA]; } } var proxy = new Proxy(target, handler); -assert(JSON.stringify(Reflect.ownKeys(proxy)) === '["foo","bar"]'); -assert(JSON.stringify(Object.getOwnPropertyNames(proxy)) === '["foo","bar"]'); -assert(JSON.stringify(Object.keys(proxy)) === '["foo","bar"]'); -assert(JSON.stringify(Object.getOwnPropertySymbols(proxy)) === '["foo","bar"]'); +array_check(Reflect.ownKeys(proxy), ["foo", "bar", symA]); +array_check(Object.getOwnPropertyNames(proxy), ["foo", "bar"]); +array_check(Object.keys(proxy), ["foo", "bar"]); +array_check(Object.getOwnPropertySymbols(proxy), [symA]); handler.ownKeys = function(target) {return Object.getOwnPropertyNames(target);}; -assert(JSON.stringify(Reflect.ownKeys(proxy)) === '["prop1","prop2"]'); -assert(JSON.stringify(Object.getOwnPropertyNames(proxy)) === '["prop1","prop2"]'); -assert(JSON.stringify(Object.keys(proxy)) === '["prop1","prop2"]'); -assert(JSON.stringify(Object.getOwnPropertySymbols(proxy)) === '["prop1","prop2"]'); +array_check(Reflect.ownKeys(proxy), ["prop1", "prop2"]); +array_check(Object.getOwnPropertyNames(proxy), ["prop1", "prop2"]); +array_check(Object.keys(proxy), ["prop1", "prop2"]); +array_check(Object.getOwnPropertySymbols(proxy), []); // test with no trap var target = { prop1: "prop1", prop2: "prop2"}; diff --git a/tests/jerry/es2015/regression-test-issue-3787.js b/tests/jerry/es2015/regression-test-issue-3787.js new file mode 100644 index 0000000000..40a4a0394f --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3787.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 symbol = Symbol("s"); +var obj = {demo: "3"}; +obj[symbol] = 3; + +var proxy = new Proxy(obj, []); +var str = JSON.stringify(proxy); + +assert(str === '{"demo":"3"}');