From 1193de88ccac6d2cbf6c1a447f40b0db29fdc6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20B=C3=A1tyai?= Date: Tue, 21 Jul 2015 13:21:19 +0200 Subject: [PATCH] Use [[DefineOwnProperty]] in Array builtins where necessary. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com --- .../ecma-builtin-array-prototype.cpp | 80 ++++++++++--------- .../builtin-objects/ecma-builtin-helpers.cpp | 48 +++++++++++ .../builtin-objects/ecma-builtin-helpers.h | 7 ++ tests/jerry/array-prototype-filter.js | 7 ++ tests/jerry/array-prototype-map.js | 7 ++ tests/jerry/array-prototype-slice.js | 7 ++ tests/jerry/array-prototype-splice.js | 7 ++ 7 files changed, 125 insertions(+), 38 deletions(-) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp index 028c38f32..74bf38db9 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp @@ -895,15 +895,18 @@ ecma_builtin_array_prototype_object_slice (ecma_value_t this_arg, /**< 'this' ar ECMA_TRY_CATCH (get_value, ecma_op_object_get (obj_p, curr_idx_str_p), ret_value); ecma_string_t *to_idx_str_p = ecma_new_ecma_string_from_uint32 (n); - /* - * 10.c.ii - * Using [[Put]] is equivalent to using [[DefineOwnProperty]] as specified the standard, - * so we use [[Put]] instead for simplicity. No need for a try-catch block since it is called - * with is_throw = false. - */ - ecma_completion_value_t put_comp_value = ecma_op_object_put (new_array_p, to_idx_str_p, get_value, false); - JERRY_ASSERT (ecma_is_completion_value_normal (put_comp_value)); - ecma_free_completion_value (put_comp_value); + + /* 10.c.ii */ + /* This will always be a simple value since 'is_throw' is false, so no need to free. */ + ecma_completion_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p, + to_idx_str_p, + get_value, + true, /* Writable */ + true, /* Enumerable */ + true, /* Configurable */ + false); + JERRY_ASSERT (ecma_is_completion_value_normal_true (put_comp)); + ecma_deref_ecma_string (to_idx_str_p); ECMA_FINALIZE (get_value); @@ -1477,16 +1480,17 @@ ecma_builtin_array_prototype_object_splice (ecma_value_t this_arg, /**< this arg ecma_string_t *idx_str_new_p = ecma_new_ecma_string_from_uint32 (k); - /* 9.c.ii - * Using [[Put]] is equivalent to using [[DefineOwnProperty]] as specified the standard, - * so we use [[Put]] instead for simplicity. No need for a try-catch block since it is called - * with is_throw = false. - */ - ECMA_TRY_CATCH (put_value, - ecma_op_object_put (new_array_p, idx_str_new_p, get_value, false), - ret_value); + /* 9.c.ii */ + /* This will always be a simple value since 'is_throw' is false, so no need to free. */ + ecma_completion_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p, + idx_str_new_p, + get_value, + true, /* Writable */ + true, /* Enumerable */ + true, /* Configurable */ + false); + JERRY_ASSERT (ecma_is_completion_value_normal_true (put_comp)); - ECMA_FINALIZE (put_value); ecma_deref_ecma_string (idx_str_new_p); ECMA_FINALIZE (get_value); } @@ -2365,15 +2369,16 @@ ecma_builtin_array_prototype_object_map (ecma_value_t this_arg, /**< this argume ECMA_TRY_CATCH (mapped_value, ecma_op_function_call (func_object_p, arg2, call_args, 3), ret_value); - /* 8.c.iii - * By definition we should use [[DefineOwnProperty]] here, but since [[Put]] will create the - * same property that we need, we can use it for simplicity. No need for a try-catch block - * since it is called with is_throw = false. - * ecma_op_to_boolean always returns a simple value, so no need to free. - */ - ecma_completion_value_t put_comp_value = ecma_op_object_put (new_array_p, index_str_p, mapped_value, false); - JERRY_ASSERT (ecma_is_completion_value_normal_true (put_comp_value)); - ecma_free_completion_value (put_comp_value); + /* 8.c.iii */ + /* This will always be a simple value since 'is_throw' is false, so no need to free. */ + ecma_completion_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p, + index_str_p, + mapped_value, + true, /* Writable */ + true, /* Enumerable */ + true, /* Configurable */ + false); + JERRY_ASSERT (ecma_is_completion_value_normal_true (put_comp)); ECMA_FINALIZE (mapped_value); ECMA_FINALIZE (current_value); @@ -2486,17 +2491,16 @@ ecma_builtin_array_prototype_object_filter (ecma_value_t this_arg, /**< this arg if (ecma_is_completion_value_normal_true (ecma_op_to_boolean (call_value))) { ecma_string_t *to_index_string_p = ecma_new_ecma_string_from_uint32 (new_array_index); - /* - * By definition we should use [[DefineOwnProperty]] here, but since [[Put]] will create the - * same property that we need, we can use it for simplicity. No need for a try-catch block - * since it is called with is_throw = false. - */ - ecma_completion_value_t put_comp_value = ecma_op_object_put (new_array_p, - to_index_string_p, - get_value, - false); - JERRY_ASSERT (ecma_is_completion_value_normal_true (put_comp_value)); - ecma_free_completion_value (put_comp_value); + + /* This will always be a simple value since 'is_throw' is false, so no need to free. */ + ecma_completion_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p, + to_index_string_p, + get_value, + true, /* Writable */ + true, /* Enumerable */ + true, /* Configurable */ + false); + JERRY_ASSERT (ecma_is_completion_value_normal_true (put_comp)); ecma_deref_ecma_string (to_index_string_p); new_array_index++; diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp index c03de0df4..c48021ebe 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp @@ -505,6 +505,54 @@ ecma_builtin_helper_string_index_normalize (ecma_number_t index, /**< index */ return norm_index; } /* ecma_builtin_helper_string_index_normalize */ +/** + * Helper function for using [[DefineOwnProperty]]. + * + * See also: + * ECMA-262 v5, 8.12.9 + * ECMA-262 v5, 15.4.5.1 + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value. + */ +ecma_completion_value_t +ecma_builtin_helper_def_prop (ecma_object_t *obj_p, /**< object */ + ecma_string_t *index_p, /**< index string */ + ecma_value_t value, /**< value */ + bool writable, /**< writable */ + bool enumerable, /**< enumerable */ + bool configurable, /**< configurable */ + bool is_throw) /**< is_throw */ +{ + ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); + + prop_desc.is_value_defined = true; + prop_desc.value = value; + + if (writable) + { + prop_desc.is_writable_defined = true; + prop_desc.is_writable = true; + } + + if (enumerable) + { + prop_desc.is_enumerable_defined = true; + prop_desc.is_enumerable = true; + } + + if (configurable) + { + prop_desc.is_configurable_defined = true; + prop_desc.is_configurable = true; + } + + return ecma_op_object_define_own_property (obj_p, + index_p, + &prop_desc, + is_throw); +} /* ecma_builtin_helper_def_prop */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h index f87a3896f..59e0565db 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h @@ -35,6 +35,13 @@ extern ecma_completion_value_t ecma_builtin_helper_array_concat_value (ecma_obje ecma_value_t); extern uint32_t ecma_builtin_helper_array_index_normalize (ecma_number_t index, uint32_t length); extern uint32_t ecma_builtin_helper_string_index_normalize (ecma_number_t index, uint32_t length); +extern ecma_completion_value_t ecma_builtin_helper_def_prop (ecma_object_t *obj_p, + ecma_string_t *index_p, + ecma_value_t value, + bool writable, + bool enumerable, + bool configurable, + bool is_throw); #ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_DATE_BUILTIN diff --git a/tests/jerry/array-prototype-filter.js b/tests/jerry/array-prototype-filter.js index ce4f28268..ad00306d9 100644 --- a/tests/jerry/array-prototype-filter.js +++ b/tests/jerry/array-prototype-filter.js @@ -44,6 +44,13 @@ assert(filtered[1] === 3); assert(filtered[2] === 5); assert(filtered[3] === 7); +var arr = [1,2]; +Array.prototype[0] = 3; +var newArr = arr.filter(function() { return true; }); +delete Array.prototype[0]; +assert(newArr.hasOwnProperty("0")); +assert(newArr[0] === 1); + // Checking behavior when unable to get length var obj = {}; Object.defineProperty(obj, 'length', { 'get' : function () {throw new ReferenceError ("foo"); } }); diff --git a/tests/jerry/array-prototype-map.js b/tests/jerry/array-prototype-map.js index 7a95ca252..93664fef1 100644 --- a/tests/jerry/array-prototype-map.js +++ b/tests/jerry/array-prototype-map.js @@ -62,6 +62,13 @@ assert (long_array.map(func).equals([0,2])); long_array[100] = 1; assert (long_array.map(func).equals([0,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,101])); +var arr = [1,2]; +Array.prototype[0] = 3; +var newArr = arr.map(function(value) { return value; }); +delete Array.prototype[0]; +assert(newArr.hasOwnProperty("0")); +assert(newArr[0] === 1); + // check behavior when unable to get length var obj = {}; Object.defineProperty(obj, 'length', { 'get' : function () {throw new ReferenceError ("foo"); } }); diff --git a/tests/jerry/array-prototype-slice.js b/tests/jerry/array-prototype-slice.js index a9d1348cc..f651c9d35 100644 --- a/tests/jerry/array-prototype-slice.js +++ b/tests/jerry/array-prototype-slice.js @@ -79,6 +79,13 @@ array[4294967293] = "bar"; var result = array.slice(-4294967297, -4294967296); assert(result.length === 0); +var arr = [1,2]; +Array.prototype[0] = 3; +var newArr = arr.slice(0, 1); +delete Array.prototype[0]; +assert(newArr.hasOwnProperty("0")); +assert(newArr[0] === 1); + // Checking behavior when unable to get length var obj = { slice : Array.prototype.slice }; Object.defineProperty(obj, 'length', { 'get' : function () { throw new ReferenceError ("foo"); } }); diff --git a/tests/jerry/array-prototype-splice.js b/tests/jerry/array-prototype-splice.js index 6b9aeaffc..7853cbd4f 100644 --- a/tests/jerry/array-prototype-splice.js +++ b/tests/jerry/array-prototype-splice.js @@ -144,6 +144,13 @@ assert(result.length === 1) assert(result[0] === "bar") assert(array[0] === "y") +var arr = [1,2]; +Array.prototype[0] = 3; +var newArr = arr.splice(0, 1); +delete Array.prototype[0]; +assert(newArr.hasOwnProperty("0")); +assert(newArr[0] === 1); + // Checking behavior when unable to get length var obj = {splice : Array.prototype.splice}; Object.defineProperty(obj, 'length', { 'get' : function () { throw new ReferenceError ("foo"); } });