From 50371ddf20589a02227f4412b25b12e7bbbc5194 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Wed, 3 Sep 2014 17:30:03 +0400 Subject: [PATCH] Implementing Array construction routine; adding unit test on array operations. --- src/libcoreint/opcodes-varg.c | 2 +- src/libcoreint/opcodes.c | 20 ++- src/libecmaoperations/ecma-array-object.c | 114 ++++++++++-- src/libecmaoperations/ecma-array-object.h | 2 +- src/libecmaoperations/ecma-get-put-value.c | 15 +- src/libecmaoperations/ecma-objects.c | 5 + tests/unit/test_array_obj.c | 192 +++++++++++++++++++++ 7 files changed, 330 insertions(+), 20 deletions(-) create mode 100644 tests/unit/test_array_obj.c diff --git a/src/libcoreint/opcodes-varg.c b/src/libcoreint/opcodes-varg.c index 2b16ed59e..fa8ff4078 100644 --- a/src/libcoreint/opcodes-varg.c +++ b/src/libcoreint/opcodes-varg.c @@ -42,7 +42,7 @@ fill_varg_list (int_data_t *int_data, /**< interpreter context */ { ecma_completion_value_t evaluate_arg_completion = run_int_loop (int_data); - if (ecma_is_completion_value_meta (evaluate_arg_completion)) + if (ecma_is_completion_value_normal (evaluate_arg_completion)) { opcode_t next_opcode = read_opcode (int_data->pos); JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); diff --git a/src/libcoreint/opcodes.c b/src/libcoreint/opcodes.c index 41645b0be..349b5c3ae 100644 --- a/src/libcoreint/opcodes.c +++ b/src/libcoreint/opcodes.c @@ -902,15 +902,17 @@ opfunc_array_decl (opcode_t opdata, /**< operation data */ { JERRY_ASSERT (args_read == args_number); - ecma_object_t *array_obj_p = ecma_op_create_array_object (arg_values, - args_number, - false); + ECMA_TRY_CATCH (array_obj_value, + ecma_op_create_array_object (arg_values, + args_number, + false), + ret_value); ret_value = set_variable_value (int_data, lhs_var_idx, - ecma_make_object_value (array_obj_p)); + array_obj_value.u.value); - ecma_deref_object (array_obj_p); + ECMA_FINALIZE (array_obj_value); } else { @@ -957,8 +959,10 @@ opfunc_obj_decl (opcode_t opdata, /**< operation data */ { ecma_completion_value_t evaluate_prop_completion = run_int_loop (int_data); - if (ecma_is_completion_value_meta (evaluate_prop_completion)) + if (ecma_is_completion_value_normal (evaluate_prop_completion)) { + JERRY_ASSERT (ecma_is_completion_value_empty (evaluate_prop_completion)); + opcode_t next_opcode = read_opcode (int_data->pos); JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); @@ -1423,8 +1427,10 @@ opfunc_with (opcode_t opdata, /**< operation data */ ecma_completion_value_t evaluation_completion = run_int_loop (int_data); - if (ecma_is_completion_value_meta (evaluation_completion)) + if (ecma_is_completion_value_normal (evaluation_completion)) { + JERRY_ASSERT (ecma_is_completion_value_empty (evaluation_completion)); + opcode_t meta_opcode = read_opcode (int_data->pos); JERRY_ASSERT (meta_opcode.op_idx == __op__idx_meta); JERRY_ASSERT (meta_opcode.data.meta.type == OPCODE_META_TYPE_END_WITH); diff --git a/src/libecmaoperations/ecma-array-object.c b/src/libecmaoperations/ecma-array-object.c index 19acb5baf..12707d10f 100644 --- a/src/libecmaoperations/ecma-array-object.c +++ b/src/libecmaoperations/ecma-array-object.c @@ -55,9 +55,10 @@ ecma_reject (bool is_throw) /**< Throw flag */ * See also: ECMA-262 v5, 15.4.2.1 * ECMA-262 v5, 15.4.2.2 * - * @return pointer to newly created Array object + * @return completion value + * Returned value must be freed with ecma_free_completion_value */ -ecma_object_t* +ecma_completion_value_t ecma_op_create_array_object (ecma_value_t *arguments_list_p, /**< list of arguments that are passed to Array constructor */ ecma_length_t arguments_list_len, /**< length of the arguments' list */ @@ -71,7 +72,83 @@ ecma_op_create_array_object (ecma_value_t *arguments_list_p, /**< list of argume JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS (arguments_list_p, arguments_list_len, is_treat_single_arg_as_length); + uint32_t length; + ecma_value_t *array_items_p; + ecma_length_t array_items_count; + + if (is_treat_single_arg_as_length + && arguments_list_len == 1 + && arguments_list_p[0].value_type == ECMA_TYPE_NUMBER) + { + ecma_number_t *num_p = ECMA_GET_POINTER (arguments_list_p[0].value); + uint32_t num_uint32 = ecma_number_to_uint32 (*num_p); + if (*num_p != ecma_uint32_to_number (num_uint32)) + { + return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE)); + } + else + { + length = num_uint32; + array_items_p = NULL; + array_items_count = 0; + } + } + else + { + length = arguments_list_len; + array_items_p = arguments_list_p; + array_items_count = arguments_list_len; + } + + FIXME (/* Set prototype to built-in Array prototype (15.4.3.1) */); + ecma_object_t *obj_p = ecma_create_object (NULL, true, ECMA_OBJECT_TYPE_ARRAY); + + ecma_property_t *class_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_CLASS); + class_prop_p->u.internal_property.value = ECMA_OBJECT_CLASS_ARRAY; + + ecma_string_t *length_magic_string_p = ecma_get_magic_string (ECMA_MAGIC_STRING_LENGTH); + ecma_number_t *length_num_p = ecma_alloc_number (); + *length_num_p = ecma_uint32_to_number (length); + + ecma_property_t *length_prop_p = ecma_create_named_data_property (obj_p, + length_magic_string_p, + true, + false, + false); + length_prop_p->u.named_data_property.value = ecma_make_number_value (length_num_p); + + ecma_deref_ecma_string (length_magic_string_p); + + for (uint32_t index = 0; + index < array_items_count; + index++) + { + ecma_string_t* item_name_string_p = ecma_new_ecma_string_from_uint32 (index); + + ecma_property_descriptor_t item_prop_desc = ecma_make_empty_property_descriptor (); + { + item_prop_desc.is_value_defined = true; + item_prop_desc.value = array_items_p [index]; + + item_prop_desc.is_writable_defined = true; + item_prop_desc.writable = ECMA_PROPERTY_WRITABLE; + + item_prop_desc.is_enumerable_defined = true; + item_prop_desc.enumerable = ECMA_PROPERTY_ENUMERABLE; + + item_prop_desc.is_configurable_defined = true; + item_prop_desc.configurable = ECMA_PROPERTY_CONFIGURABLE; + } + + ecma_op_object_define_own_property (obj_p, + item_name_string_p, + item_prop_desc, + false); + + ecma_deref_ecma_string (item_name_string_p); + } + + return ecma_make_normal_completion_value (ecma_make_object_value (obj_p)); } /* ecma_op_create_array_object */ /** @@ -177,8 +254,8 @@ ecma_op_array_object_define_own_property (ecma_object_t *obj_p, /**< the array o uint32_t old_len_uint32 = ecma_number_to_uint32 (*num_p); // 3. - bool is_property_name_equal_length = (ecma_compare_ecma_strings (property_name_p, - magic_string_length_p) == 0); + bool is_property_name_equal_length = ecma_compare_ecma_strings (property_name_p, + magic_string_length_p); ecma_deref_ecma_string (magic_string_length_p); @@ -332,13 +409,30 @@ ecma_op_array_object_define_own_property (ecma_object_t *obj_p, /**< the array o else { // 4.a. - ecma_number_t number = ecma_string_to_number (property_name_p); - uint32_t index = ecma_number_to_uint32 (number); + uint32_t index; + bool is_index; - TODO (Check if array index recognition is done according to ECMA); + if (property_name_p->container == ECMA_STRING_CONTAINER_UINT32_IN_DESC) + { + index = property_name_p->u.uint32_number; + is_index = true; + } + else + { + ecma_number_t number = ecma_string_to_number (property_name_p); + index = ecma_number_to_uint32 (number); - if (index >= ECMA_MAX_VALUE_OF_VALID_ARRAY_INDEX - || ecma_uint32_to_number (index) != number) + ecma_string_t *to_uint32_to_string_p = ecma_new_ecma_string_from_uint32 (index); + + is_index = ecma_compare_ecma_strings (property_name_p, + to_uint32_to_string_p); + + ecma_deref_ecma_string (to_uint32_to_string_p); + } + + is_index = is_index && (index != ECMA_MAX_VALUE_OF_VALID_ARRAY_INDEX); + + if (!is_index) { // 5. return ecma_op_general_object_define_own_property (obj_p, diff --git a/src/libecmaoperations/ecma-array-object.h b/src/libecmaoperations/ecma-array-object.h index 5b81c5bff..577dfcbcc 100644 --- a/src/libecmaoperations/ecma-array-object.h +++ b/src/libecmaoperations/ecma-array-object.h @@ -25,7 +25,7 @@ * @{ */ -extern ecma_object_t* +extern ecma_completion_value_t ecma_op_create_array_object (ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len, bool is_treat_single_arg_as_length); diff --git a/src/libecmaoperations/ecma-get-put-value.c b/src/libecmaoperations/ecma-get-put-value.c index 05b1a260a..d2c6cf0fe 100644 --- a/src/libecmaoperations/ecma-get-put-value.c +++ b/src/libecmaoperations/ecma-get-put-value.c @@ -183,7 +183,20 @@ ecma_op_put_value (ecma_reference_t ref, /**< ECMA-reference */ JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); - return ecma_op_object_put (obj_p, ref.referenced_name_p, value, ref.is_strict); + ecma_completion_value_t ret_value; + + ECMA_TRY_CATCH (put_completion, + ecma_op_object_put (obj_p, + ref.referenced_name_p, + value, + ref.is_strict), + ret_value); + + ret_value = ecma_make_empty_completion_value (); + + ECMA_FINALIZE (put_completion); + + return ret_value; } else { diff --git a/src/libecmaoperations/ecma-objects.c b/src/libecmaoperations/ecma-objects.c index 4d6e67195..b0d86386f 100644 --- a/src/libecmaoperations/ecma-objects.c +++ b/src/libecmaoperations/ecma-objects.c @@ -15,6 +15,7 @@ #include "ecma-exceptions.h" #include "ecma-globals.h" +#include "ecma-array-object.h" #include "ecma-function-object.h" #include "ecma-objects-arguments.h" #include "ecma-objects-general.h" @@ -402,6 +403,10 @@ ecma_op_object_define_own_property (ecma_object_t *obj_p, /**< the object */ } case ECMA_OBJECT_TYPE_ARRAY: + { + return ecma_op_array_object_define_own_property (obj_p, property_name_p, property_desc, is_throw); + } + case ECMA_OBJECT_TYPE_HOST: { JERRY_UNIMPLEMENTED(); diff --git a/tests/unit/test_array_obj.c b/tests/unit/test_array_obj.c new file mode 100644 index 000000000..7765def1c --- /dev/null +++ b/tests/unit/test_array_obj.c @@ -0,0 +1,192 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#include "globals.h" +#include "interpreter.h" +#include "mem-allocator.h" +#include "opcodes.h" +#include "serializer.h" + +/** + * Unit test's main function. + */ +int +main( int __unused argc, + char __unused **argv) +{ + const opcode_t test_program[] = { + [ 0] = getop_reg_var_decl (240, 255), + [ 1] = getop_jmp_down (2), + [ 2] = getop_exitval (1), + + /* var a, b; */ + [ 3] = getop_var_decl (0), + [ 4] = getop_var_decl (1), + + /* b = null; */ + [ 5] = getop_assignment (1, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_NULL), + + /* a = [12, 'length', b]; */ + [ 6] = getop_array_decl (0, 3), + [ 7] = getop_assignment (240, OPCODE_ARG_TYPE_SMALLINT, 12), + [ 8] = getop_meta (OPCODE_META_TYPE_VARG, 240, 255), + [ 9] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 2), + [10] = getop_meta (OPCODE_META_TYPE_VARG, 240, 255), + [11] = getop_assignment (240, OPCODE_ARG_TYPE_VARIABLE, 1), + [12] = getop_meta (OPCODE_META_TYPE_VARG, 240, 255), + + /* assert (a.length === 3); */ + [13] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 2), + [14] = getop_prop_getter (240, 0, 240), + [15] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 3), + [16] = getop_equal_value_type (240, 240, 241), + [17] = getop_is_false_jmp (240, 2), + + /* assert (a[0] === 12.0); */ + [18] = getop_assignment (240, OPCODE_ARG_TYPE_SMALLINT, 0), + [19] = getop_prop_getter (240, 0, 240), + [20] = getop_assignment (241, OPCODE_ARG_TYPE_NUMBER, 5), + [21] = getop_equal_value_type (240, 240, 241), + [22] = getop_is_false_jmp (240, 2), + + /* assert (a['1'] === 'length'); */ + [23] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 3), + [24] = getop_prop_getter (240, 0, 240), + [25] = getop_assignment (241, OPCODE_ARG_TYPE_STRING, 2), + [26] = getop_equal_value_type (240, 240, 241), + [27] = getop_is_false_jmp (240, 2), + + /* assert (a[2.0] === null); */ + [28] = getop_assignment (240, OPCODE_ARG_TYPE_NUMBER, 4), + [29] = getop_prop_getter (240, 0, 240), + [30] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_NULL), + [31] = getop_equal_value_type (240, 240, 241), + [32] = getop_is_false_jmp (240, 2), + + /* assert (a[2.5] === undefined); */ + [33] = getop_assignment (240, OPCODE_ARG_TYPE_NUMBER, 6), + [34] = getop_prop_getter (240, 0, 240), + [35] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_UNDEFINED), + [36] = getop_equal_value_type (240, 240, 241), + [37] = getop_is_false_jmp (240, 2), + + /* a.length = 1; */ + [38] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 2), + [39] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 1), + [40] = getop_prop_setter (0, 240, 241), + + /* assert (a.length === 1); */ + [41] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 2), + [42] = getop_prop_getter (240, 0, 240), + [43] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 1), + [44] = getop_equal_value_type (240, 240, 241), + [45] = getop_is_false_jmp (240, 2), + + /* assert (a[0] === 12.0); */ + [46] = getop_assignment (240, OPCODE_ARG_TYPE_SMALLINT, 0), + [47] = getop_prop_getter (240, 0, 240), + [48] = getop_assignment (241, OPCODE_ARG_TYPE_NUMBER, 5), + [49] = getop_equal_value_type (240, 240, 241), + [50] = getop_is_false_jmp (240, 2), + + /* assert (a['1'] === undefined); */ + [51] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 3), + [52] = getop_prop_getter (240, 0, 240), + [53] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_UNDEFINED), + [54] = getop_equal_value_type (240, 240, 241), + [55] = getop_is_false_jmp (240, 2), + + /* assert (a[2.0] === undefined); */ + [56] = getop_assignment (240, OPCODE_ARG_TYPE_NUMBER, 4), + [57] = getop_prop_getter (240, 0, 240), + [58] = getop_equal_value_type (240, 240, 241), + [59] = getop_is_false_jmp (240, 2), + + /* a.length = 8; */ + [60] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 2), + [61] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 8), + [62] = getop_prop_setter (0, 240, 241), + + /* assert (a.length === 8); */ + [63] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 2), + [64] = getop_prop_getter (240, 0, 240), + [65] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 8), + [66] = getop_equal_value_type (240, 240, 241), + [67] = getop_is_false_jmp (240, 2), + + /* a[10] = true; */ + [68] = getop_assignment (240, OPCODE_ARG_TYPE_SMALLINT, 10), + [69] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_TRUE), + [70] = getop_prop_setter (0, 240, 241), + + /* assert (a.length === 11); */ + [71] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 2), + [72] = getop_prop_getter (240, 0, 240), + [73] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 11), + [74] = getop_equal_value_type (240, 240, 241), + [75] = getop_is_false_jmp (240, 2), + + /* assert (a[0] === 12.0); */ + [76] = getop_assignment (240, OPCODE_ARG_TYPE_SMALLINT, 0), + [77] = getop_prop_getter (240, 0, 240), + [78] = getop_assignment (241, OPCODE_ARG_TYPE_NUMBER, 5), + [79] = getop_equal_value_type (240, 240, 241), + [80] = getop_is_false_jmp (240, 2), + + /* assert (a['1'] === undefined); */ + [81] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 3), + [82] = getop_prop_getter (240, 0, 240), + [83] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_UNDEFINED), + [84] = getop_equal_value_type (240, 240, 241), + [85] = getop_is_false_jmp (240, 2), + + /* assert (a[2.0] === undefined); */ + [86] = getop_assignment (240, OPCODE_ARG_TYPE_NUMBER, 4), + [87] = getop_prop_getter (240, 0, 240), + [88] = getop_equal_value_type (240, 240, 241), + [89] = getop_is_false_jmp (240, 2), + + /* assert (a[17] === true); */ + [90] = getop_assignment (240, OPCODE_ARG_TYPE_SMALLINT, 10), + [91] = getop_prop_getter (240, 0, 240), + [92] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_TRUE), + [93] = getop_equal_value_type (240, 240, 241), + [94] = getop_is_false_jmp (240, 2), + + [95] = getop_exitval (0), + }; + + mem_init(); + serializer_init (false); + + const char *strings[] = { "a", + "b", + "length", + "1" }; + ecma_number_t nums [] = { 2.0, + 12.0, + 2.5 }; + uint16_t offset = serializer_dump_strings( strings, 4); + serializer_dump_nums( nums, 3, offset, 4); + + init_int( test_program); + + bool status = run_int(); + + serializer_free (); + mem_finalize (false); + + return (status ? 0 : 1); +} /* main */