/** * The Object object's 'getOwnPropertyNames' routine * * See also: * ECMA-262 v5, 15.2.3.4 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_get_own_property_names (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); if (!ecma_is_value_object (arg)) { /* 1. */ ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg); /* 2-5. */ ret_value = ecma_builtin_helper_object_get_properties (obj_p, false); } return ret_value; } /* ecma_builtin_object_object_get_own_property_names */
/** * The Object object's 'preventExtensions' routine * * See also: * ECMA-262 v5, 15.2.3.10 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_prevent_extensions (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); if (!ecma_is_value_object (arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg); ecma_set_object_extensible (obj_p, false); ret_value = ecma_make_normal_completion_value (ecma_copy_value (arg, true)); } return ret_value; } /* ecma_builtin_object_object_prevent_extensions */
/** * [[Delete]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 8.12.7 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_general_object_delete (ecma_object_t *obj_p, /**< the object */ ecma_string_t *property_name_p, /**< property name */ bool is_throw) /**< flag that controls failure handling */ { JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); JERRY_ASSERT (property_name_p != NULL); // 1. ecma_property_t *desc_p = ecma_op_object_get_own_property (obj_p, property_name_p); // 2. if (desc_p == NULL) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } // 3. if (ecma_is_property_configurable (desc_p)) { // a. ecma_delete_property (obj_p, desc_p); // b. return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } else if (is_throw) { // 4. return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { // 5. return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); } JERRY_UNREACHABLE (); } /* ecma_op_general_object_delete */
/** * GetValue operation part (lexical environment base or unresolvable reference). * * See also: ECMA-262 v5, 8.7.1, sections 3 and 5 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ ecma_completion_value_t ecma_op_get_value_lex_env_base (ecma_object_t *ref_base_lex_env_p, /**< reference's base (lexical environment) */ ecma_string_t *var_name_string_p, /**< variable name */ bool is_strict) /**< flag indicating strict mode */ { const bool is_unresolvable_reference = (ref_base_lex_env_p == NULL); // 3. if (unlikely (is_unresolvable_reference)) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_REFERENCE)); } // 5. JERRY_ASSERT (ref_base_lex_env_p != NULL && ecma_is_lexical_environment (ref_base_lex_env_p)); // 5.a return ecma_op_get_binding_value (ref_base_lex_env_p, var_name_string_p, is_strict); } /* ecma_op_get_value_lex_env_base */
/** * The Date.prototype object's 'getTime' routine * * See also: * ECMA-262 v5, 15.9.5.9 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_date_prototype_get_time (ecma_value_t this_arg) /**< this argument */ { if (ecma_is_value_object (this_arg)) { ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); if (ecma_object_get_class_name (obj_p) == LIT_MAGIC_STRING_DATE_UL) { ecma_property_t *prim_value_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE); ecma_number_t *prim_value_num_p = ECMA_GET_NON_NULL_POINTER (ecma_number_t, prim_value_prop_p->u.internal_property.value); ecma_number_t *ret_num_p = ecma_alloc_number (); *ret_num_p = *prim_value_num_p; return ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p)); } } return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } /* ecma_builtin_date_prototype_get_time */
/** * The Object object's 'isExtensible' routine * * See also: * ECMA-262 v5, 15.2.3.13 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_is_extensible (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); if (!ecma_is_value_object (arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg); bool extensible = ecma_get_object_extensible (obj_p); ret_value = ecma_make_simple_completion_value (extensible ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } return ret_value; } /* ecma_builtin_object_object_is_extensible */
/** * The Date.prototype object's 'toISOString' routine * * See also: * ECMA-262 v5, 15.9.5.43 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_date_prototype_to_iso_string (ecma_value_t this_arg) /**< this argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ECMA_TRY_CATCH (prim_value, ecma_date_get_primitive_value (this_arg), ret_value); ecma_number_t *prim_num_p = ecma_get_number_from_value (prim_value); if (ecma_number_is_nan (*prim_num_p) || ecma_number_is_infinity (*prim_num_p)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE)); } else { ret_value = ecma_date_value_to_iso_string (*prim_num_p); } ECMA_FINALIZE (prim_value); return ret_value; } /* ecma_builtin_date_prototype_to_iso_string */
/** * The Object.prototype object's 'toLocaleString' routine * * See also: * ECMA-262 v5, 15.2.4.3 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_prototype_object_to_locale_string (ecma_value_t this_arg) /**< this argument */ { ecma_completion_value_t return_value = ecma_make_empty_completion_value (); /* 1. */ ECMA_TRY_CATCH (obj_val, ecma_op_to_object (this_arg), return_value); ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); ecma_string_t *to_string_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_TO_STRING_UL); /* 2. */ ECMA_TRY_CATCH (to_string_val, ecma_op_object_get (obj_p, to_string_magic_string_p), return_value); /* 3. */ if (!ecma_op_is_callable (to_string_val)) { return_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { /* 4. */ ecma_object_t *to_string_func_obj_p = ecma_get_object_from_value (to_string_val); return_value = ecma_op_function_call (to_string_func_obj_p, this_arg, NULL); } ECMA_FINALIZE (to_string_val); ecma_deref_ecma_string (to_string_magic_string_p); ECMA_FINALIZE (obj_val); return return_value; } /* ecma_builtin_object_prototype_object_to_locale_string */
/** * The RegExp.prototype object's 'compile' routine * * See also: * ECMA-262 v5, B.2.5.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument */ ecma_value_t pattern_arg, /**< pattern or RegExp object */ ecma_value_t flags_arg) /**< flags */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg); if (ecma_object_get_class_name (this_obj_p) != LIT_MAGIC_STRING_REGEXP_UL) { /* Compile can only be called on RegExp objects. */ ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_string_t *pattern_string_p = NULL; uint16_t flags = 0; if (ecma_is_value_object (pattern_arg) && ecma_object_get_class_name (ecma_get_object_from_value (pattern_arg)) == LIT_MAGIC_STRING_REGEXP_UL) { if (!ecma_is_value_undefined (flags_arg)) { ret_value = ecma_raise_type_error ("Invalid argument of RegExp compile."); } else { /* Compile from existing RegExp pbject. */ ecma_object_t *target_p = ecma_get_object_from_value (pattern_arg); /* Get source. */ ecma_string_t *magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE); ecma_property_t *prop_p = ecma_get_named_data_property (target_p, magic_string_p); pattern_string_p = ecma_get_string_from_value (ecma_get_named_data_property_value (prop_p)); ecma_deref_ecma_string (magic_string_p); /* Get flags. */ magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL); prop_p = ecma_get_named_data_property (target_p, magic_string_p); if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p))) { flags |= RE_FLAG_GLOBAL; } ecma_deref_ecma_string (magic_string_p); magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL); prop_p = ecma_get_named_data_property (target_p, magic_string_p); if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p))) { flags |= RE_FLAG_IGNORE_CASE; } ecma_deref_ecma_string (magic_string_p); magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE); prop_p = ecma_get_named_data_property (target_p, magic_string_p); if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p))) { flags |= RE_FLAG_MULTILINE; } ecma_deref_ecma_string (magic_string_p); /* Get bytecode property. */ ecma_property_t *bc_prop_p = ecma_get_internal_property (this_obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); /* FIXME: "We currently have to re-compile the bytecode, because * we can't copy it without knowing its length." */ re_compiled_code_t *new_bc_p = NULL; ecma_completion_value_t bc_comp = re_compile_bytecode (&new_bc_p, pattern_string_p, flags); /* Should always succeed, since we're compiling from a source that has been compiled previously. */ JERRY_ASSERT (ecma_is_completion_value_empty (bc_comp)); re_compiled_code_t *old_bc_p = ECMA_GET_POINTER (re_compiled_code_t, bc_prop_p->u.internal_property.value); if (old_bc_p != NULL) { /* Free the old bytecode */ ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p); } ECMA_SET_POINTER (bc_prop_p->u.internal_property.value, new_bc_p); re_initialize_props (this_obj_p, pattern_string_p, flags); ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)); } } else { /* Get source string. */ if (!ecma_is_value_undefined (pattern_arg)) { ECMA_TRY_CATCH (regexp_str_value, ecma_op_to_string (pattern_arg), ret_value); if (ecma_string_get_length (ecma_get_string_from_value (regexp_str_value)) == 0) { pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP); } else { pattern_string_p = ecma_copy_or_ref_ecma_string (ecma_get_string_from_value (regexp_str_value)); } ECMA_FINALIZE (regexp_str_value); } else { pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP); } /* Parse flags. */ if (ecma_is_completion_value_empty (ret_value) && !ecma_is_value_undefined (flags_arg)) { ECMA_TRY_CATCH (flags_str_value, ecma_op_to_string (flags_arg), ret_value); ECMA_TRY_CATCH (flags_dummy, re_parse_regexp_flags (ecma_get_string_from_value (flags_str_value), &flags), ret_value); ECMA_FINALIZE (flags_dummy); ECMA_FINALIZE (flags_str_value); } if (ecma_is_completion_value_empty (ret_value)) { ecma_property_t *bc_prop_p = ecma_get_internal_property (this_obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); /* Try to compile bytecode from new source. */ re_compiled_code_t *new_bc_p = NULL; ECMA_TRY_CATCH (bc_dummy, re_compile_bytecode (&new_bc_p, pattern_string_p, flags), ret_value); re_compiled_code_t *old_bc_p = ECMA_GET_POINTER (re_compiled_code_t, bc_prop_p->u.internal_property.value); if (old_bc_p != NULL) { /* Free the old bytecode */ ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p); } ECMA_SET_POINTER (bc_prop_p->u.internal_property.value, new_bc_p); re_initialize_props (this_obj_p, pattern_string_p, flags); ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)); ECMA_FINALIZE (bc_dummy); } if (pattern_string_p != NULL) { ecma_deref_ecma_string (pattern_string_p); } } } return ret_value; } /* ecma_builtin_regexp_prototype_compile */
/** * [[DefaultValue]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 8.12.8 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_general_object_default_value (ecma_object_t *obj_p, /**< the object */ ecma_preferred_type_hint_t hint) /**< hint on preferred result type */ { JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); if (hint == ECMA_PREFERRED_TYPE_NO) { if (ecma_object_get_class_name (obj_p) == LIT_MAGIC_STRING_DATE_UL) { hint = ECMA_PREFERRED_TYPE_STRING; } else { hint = ECMA_PREFERRED_TYPE_NUMBER; } } for (uint32_t i = 1; i <= 2; i++) { lit_magic_string_id_t function_name_magic_string_id; if ((i == 1 && hint == ECMA_PREFERRED_TYPE_STRING) || (i == 2 && hint == ECMA_PREFERRED_TYPE_NUMBER)) { function_name_magic_string_id = LIT_MAGIC_STRING_TO_STRING_UL; } else { function_name_magic_string_id = LIT_MAGIC_STRING_VALUE_OF_UL; } ecma_string_t *function_name_p = ecma_get_magic_string (function_name_magic_string_id); ecma_completion_value_t function_value_get_completion = ecma_op_object_get (obj_p, function_name_p); ecma_deref_ecma_string (function_name_p); if (!ecma_is_completion_value_normal (function_value_get_completion)) { return function_value_get_completion; } ecma_completion_value_t call_completion = ecma_make_empty_completion_value (); if (ecma_op_is_callable (ecma_get_completion_value_value (function_value_get_completion))) { ecma_object_t *func_obj_p = ecma_get_object_from_completion_value (function_value_get_completion); call_completion = ecma_op_function_call (func_obj_p, ecma_make_object_value (obj_p), NULL); } ecma_free_completion_value (function_value_get_completion); if (!ecma_is_completion_value_normal (call_completion)) { return call_completion; } if (!ecma_is_completion_value_empty (call_completion) && !ecma_is_value_object (ecma_get_completion_value_value (call_completion))) { return call_completion; } ecma_free_completion_value (call_completion); } return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } /* ecma_op_general_object_default_value */
/** * The Function.prototype object's 'apply' routine * * See also: * ECMA-262 v5, 15.3.4.3 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_function_prototype_object_apply (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg1, /**< first argument */ ecma_value_t arg2) /**< second argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 1. */ if (!ecma_op_is_callable (this_arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *func_obj_p = ecma_get_object_from_value (this_arg); /* 2. */ if (ecma_is_value_null (arg2) || ecma_is_value_undefined (arg2)) { ret_value = ecma_op_function_call (func_obj_p, arg1, NULL, 0); } else { /* 3. */ if (!ecma_is_value_object (arg2)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg2); ecma_string_t *length_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); /* 4. */ ECMA_TRY_CATCH (length_value, ecma_op_object_get (obj_p, length_magic_string_p), ret_value); ECMA_OP_TO_NUMBER_TRY_CATCH (length_number, length_value, ret_value); /* 5. */ const uint32_t length = ecma_number_to_uint32 (length_number); /* 6. */ MEM_DEFINE_LOCAL_ARRAY (arguments_list_p, length, ecma_value_t); uint32_t last_index = 0; /* 7. */ for (uint32_t index = 0; index < length && ecma_is_completion_value_empty (ret_value); index++) { ecma_string_t *curr_idx_str_p = ecma_new_ecma_string_from_uint32 (index); ECMA_TRY_CATCH (get_value, ecma_op_object_get (obj_p, curr_idx_str_p), ret_value); arguments_list_p[index] = ecma_copy_value (get_value, true); last_index = index + 1; ECMA_FINALIZE (get_value); ecma_deref_ecma_string (curr_idx_str_p); } if (ecma_is_completion_value_empty (ret_value)) { JERRY_ASSERT (last_index == length); ret_value = ecma_op_function_call (func_obj_p, arg1, arguments_list_p, length); } for (uint32_t index = 0; index < last_index; index++) { ecma_free_value (arguments_list_p[index], true); } MEM_FINALIZE_LOCAL_ARRAY (arguments_list_p); ECMA_OP_TO_NUMBER_FINALIZE (length_number); ECMA_FINALIZE (length_value); ecma_deref_ecma_string (length_magic_string_p); } } } return ret_value; } /* ecma_builtin_function_prototype_object_apply */
/** * [[Put]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 8.12.5 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_general_object_put (ecma_object_t *obj_p, /**< the object */ ecma_string_t *property_name_p, /**< property name */ ecma_value_t value, /**< ecma-value */ bool is_throw) /**< flag that controls failure handling */ { JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); JERRY_ASSERT (property_name_p != NULL); // 1. if (!ecma_op_object_can_put (obj_p, property_name_p)) { if (is_throw) { // a. return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { // b. return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); } } // 2. ecma_property_t *own_desc_p = ecma_op_object_get_own_property (obj_p, property_name_p); // 3. if (own_desc_p != NULL && own_desc_p->type == ECMA_PROPERTY_NAMEDDATA) { // a. ecma_property_descriptor_t value_desc = ecma_make_empty_property_descriptor (); { value_desc.is_value_defined = true; value_desc.value = value; } // b., c. return ecma_op_object_define_own_property (obj_p, property_name_p, &value_desc, is_throw); } // 4. ecma_property_t *desc_p = ecma_op_object_get_property (obj_p, property_name_p); // 5. if (desc_p != NULL && desc_p->type == ECMA_PROPERTY_NAMEDACCESSOR) { // a. ecma_object_t *setter_p = ecma_get_named_accessor_property_setter (desc_p); JERRY_ASSERT (setter_p != NULL); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ECMA_TRY_CATCH (call_ret, ecma_op_function_call_array_args (setter_p, ecma_make_object_value (obj_p), &value, 1), ret_value); ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); ECMA_FINALIZE (call_ret); return ret_value; } else { // 6.a., 6.b. return ecma_builtin_helper_def_prop (obj_p, property_name_p, value, true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ is_throw); /* Failure handling */ } JERRY_UNREACHABLE (); } /* ecma_op_general_object_put */
/** * [[DefineOwnProperty]] ecma array object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * 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_op_array_object_define_own_property (ecma_object_t *obj_p, /**< the array object */ ecma_string_t *property_name_p, /**< property name */ const ecma_property_descriptor_t* property_desc_p, /**< property descriptor */ bool is_throw) /**< flag that controls failure handling */ { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY); // 1. ecma_string_t* magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_property_t *len_prop_p = ecma_op_object_get_own_property (obj_p, magic_string_length_p); JERRY_ASSERT (len_prop_p != NULL && len_prop_p->type == ECMA_PROPERTY_NAMEDDATA); // 2. ecma_value_t old_len_value = ecma_get_named_data_property_value (len_prop_p); ecma_number_t *num_p = ecma_get_number_from_value (old_len_value); 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); ecma_deref_ecma_string (magic_string_length_p); if (is_property_name_equal_length) { // a. if (!property_desc_p->is_value_defined) { // i. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } ecma_number_t new_len_num; // c. ecma_completion_value_t completion = ecma_op_to_number (property_desc_p->value); if (ecma_is_completion_value_throw (completion)) { return completion; } JERRY_ASSERT (ecma_is_completion_value_normal (completion) && ecma_is_value_number (ecma_get_completion_value_value (completion))); new_len_num = *ecma_get_number_from_completion_value (completion); ecma_free_completion_value (completion); uint32_t new_len_uint32 = ecma_number_to_uint32 (new_len_num); // d. if (ecma_uint32_to_number (new_len_uint32) != new_len_num) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE)); } else { // b., e. ecma_number_t *new_len_num_p = ecma_alloc_number (); *new_len_num_p = new_len_num; ecma_property_descriptor_t new_len_property_desc = *property_desc_p; new_len_property_desc.value = ecma_make_number_value (new_len_num_p); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // f. if (new_len_uint32 >= old_len_uint32) { // i. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ret_value = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); } else { // g. if (!ecma_is_property_writable (len_prop_p)) { ret_value = ecma_reject (is_throw); } else { // h. bool new_writable; if (!new_len_property_desc.is_writable_defined || new_len_property_desc.is_writable) { new_writable = true; } else { // ii. new_writable = false; // iii. new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = true; } // j. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); /* Handling normal false and throw values */ if (!ecma_is_completion_value_normal_true (succeeded)) { JERRY_ASSERT (ecma_is_completion_value_normal_false (succeeded) || ecma_is_completion_value_throw (succeeded)); // k. ret_value = succeeded; } else { // l JERRY_ASSERT (new_len_uint32 < old_len_uint32); bool reduce_succeeded = true; while (new_len_uint32 < old_len_uint32) { // i old_len_uint32--; // ii ecma_string_t *old_length_string_p = ecma_new_ecma_string_from_uint32 (old_len_uint32); ecma_completion_value_t delete_succeeded = ecma_op_object_delete (obj_p, old_length_string_p, false); ecma_deref_ecma_string (old_length_string_p); // iii if (ecma_is_completion_value_normal_false (delete_succeeded)) { JERRY_ASSERT (ecma_is_value_number (new_len_property_desc.value)); ecma_number_t *new_len_num_p = ecma_get_number_from_value (new_len_property_desc.value); // 1. *new_len_num_p = ecma_uint32_to_number (old_len_uint32 + 1); // 2. if (!new_writable) { new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = false; } // 3. ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_completion_value_t completion = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (completion)); reduce_succeeded = false; break; } } if (!reduce_succeeded) { ret_value = ecma_reject (is_throw); } else { // m. if (!new_writable) { ecma_property_descriptor_t prop_desc_not_writable = ecma_make_empty_property_descriptor (); prop_desc_not_writable.is_writable_defined = true; prop_desc_not_writable.is_writable = false; ecma_completion_value_t completion_set_not_writable; magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); completion_set_not_writable = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &prop_desc_not_writable, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion_set_not_writable)); } ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } } } } ecma_dealloc_number (new_len_num_p); return ret_value; } JERRY_UNREACHABLE (); } else { // 4.a. uint32_t index; if (!ecma_string_get_array_index (property_name_p, &index)) { // 5. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } // 4. // b. if (index >= old_len_uint32 && !ecma_is_property_writable (len_prop_p)) { return ecma_reject (is_throw); } // c. ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, false); // d. JERRY_ASSERT (ecma_is_completion_value_normal_true (succeeded) || ecma_is_completion_value_normal_false (succeeded)); if (ecma_is_completion_value_normal_false (succeeded)) { return ecma_reject (is_throw); } // e. if (index >= old_len_uint32) { // i., ii. ecma_number_t *num_p = ecma_alloc_number (); *num_p = ecma_number_add (ecma_uint32_to_number (index), ECMA_NUMBER_ONE); ecma_named_data_property_assign_value (obj_p, len_prop_p, ecma_make_number_value (num_p)); ecma_dealloc_number (num_p); } // f. return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } JERRY_UNREACHABLE (); } /* ecma_op_array_object_define_own_property */
/** * The Object object's 'defineProperties' routine * * See also: * ECMA-262 v5, 15.2.3.7 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_define_properties (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg1, /**< routine's first argument */ ecma_value_t arg2) /**< routine's second argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 1. if (!ecma_is_value_object (arg1)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg1); // 2. ECMA_TRY_CATCH (props, ecma_op_to_object (arg2), ret_value); ecma_object_t *props_p = ecma_get_object_from_value (props); // 3. ecma_collection_header_t *prop_names_p = ecma_op_object_get_property_names (props_p, false, true, false); uint32_t property_number = prop_names_p->unit_number; ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, prop_names_p); // 4. MEM_DEFINE_LOCAL_ARRAY (property_descriptors, property_number, ecma_property_descriptor_t); uint32_t property_descriptor_number = 0; while (ecma_collection_iterator_next (&iter) && ecma_is_completion_value_empty (ret_value)) { // 5.a ECMA_TRY_CATCH (desc_obj, ecma_op_object_get (props_p, ecma_get_string_from_value (*iter.current_value_p)), ret_value); // 5.b ECMA_TRY_CATCH (conv_result, ecma_op_to_property_descriptor (desc_obj, &property_descriptors[property_descriptor_number]), ret_value); property_descriptor_number++; ECMA_FINALIZE (conv_result); ECMA_FINALIZE (desc_obj); } // 6. ecma_collection_iterator_init (&iter, prop_names_p); for (uint32_t index = 0; index < property_number && ecma_is_completion_value_empty (ret_value); index++) { bool is_next = ecma_collection_iterator_next (&iter); JERRY_ASSERT (is_next); ECMA_TRY_CATCH (define_own_prop_ret, ecma_op_object_define_own_property (obj_p, ecma_get_string_from_value (*iter.current_value_p), &property_descriptors[index], true), ret_value); ECMA_FINALIZE (define_own_prop_ret); } // Clean up for (uint32_t index = 0; index < property_descriptor_number; index++) { ecma_free_property_descriptor (&property_descriptors[index]); } MEM_FINALIZE_LOCAL_ARRAY (property_descriptors); ecma_free_values_collection (prop_names_p, true); // 7. if (ecma_is_completion_value_empty (ret_value)) { ret_value = ecma_make_normal_completion_value (ecma_copy_value (arg1, true)); } ECMA_FINALIZE (props); } return ret_value; } /* ecma_builtin_object_object_define_properties */
/** * Perform 'eval' with code stored in continuous character buffer * * See also: * ecma_op_eval * ECMA-262 v5, 15.1.2.1 (steps 2 to 8) * * @return completion value */ ecma_completion_value_t ecma_op_eval_chars_buffer (const jerry_api_char_t *code_p, /**< code characters buffer */ size_t code_buffer_size, /**< size of the buffer */ bool is_direct, /**< is eval called directly (ECMA-262 v5, 15.1.2.1.1) */ bool is_called_from_strict_mode_code) /**< is eval is called from strict mode code */ { JERRY_ASSERT (code_p != NULL); ecma_completion_value_t completion; const vm_instr_t *instrs_p; jsp_status_t parse_status; bool is_strict_call = (is_direct && is_called_from_strict_mode_code); parse_status = parser_parse_eval (code_p, code_buffer_size, is_strict_call, &instrs_p); if (parse_status == JSP_STATUS_SYNTAX_ERROR) { completion = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_SYNTAX)); } else if (parse_status == JSP_STATUS_REFERENCE_ERROR) { completion = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_REFERENCE)); } else { JERRY_ASSERT (parse_status == JSP_STATUS_OK); vm_instr_counter_t first_instr_index = 0u; bool is_strict_prologue = false; opcode_scope_code_flags_t scope_flags = vm_get_scope_flags (instrs_p, first_instr_index++); if (scope_flags & OPCODE_SCOPE_CODE_FLAGS_STRICT) { is_strict_prologue = true; } bool is_strict = (is_strict_call || is_strict_prologue); ecma_value_t this_binding; ecma_object_t *lex_env_p; /* ECMA-262 v5, 10.4.2 */ if (is_direct) { this_binding = vm_get_this_binding (); lex_env_p = vm_get_lex_env (); } else { this_binding = ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL)); lex_env_p = ecma_get_global_environment (); } if (is_strict) { ecma_object_t *strict_lex_env_p = ecma_create_decl_lex_env (lex_env_p); ecma_deref_object (lex_env_p); lex_env_p = strict_lex_env_p; } completion = vm_run_from_pos (instrs_p, first_instr_index, this_binding, lex_env_p, is_strict, true); if (ecma_is_completion_value_return (completion)) { completion = ecma_make_normal_completion_value (ecma_get_completion_value_value (completion)); } else { JERRY_ASSERT (ecma_is_completion_value_throw (completion)); } ecma_deref_object (lex_env_p); ecma_free_value (this_binding, true); } return completion; } /* ecma_op_eval_chars_buffer */
/** * ToPropertyDescriptor operation. * * See also: * ECMA-262 v5, 8.10.5 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ ecma_property_descriptor_t *out_prop_desc_p) /**< out: filled property descriptor if return value is normal empty completion value */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 1. if (!ecma_is_value_object (obj_value)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (obj_value); // 2. ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); // 3. ecma_string_t *enumerable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ENUMERABLE); if (ecma_op_object_get_property (obj_p, enumerable_magic_string_p) != NULL) { ECMA_TRY_CATCH (enumerable_prop_value, ecma_op_object_get (obj_p, enumerable_magic_string_p), ret_value); ECMA_TRY_CATCH (boolean_enumerable_prop_value, ecma_op_to_boolean (enumerable_prop_value), ret_value); prop_desc.is_enumerable_defined = true; if (ecma_is_value_true (boolean_enumerable_prop_value)) { prop_desc.is_enumerable = true; } else { JERRY_ASSERT (ecma_is_value_boolean (boolean_enumerable_prop_value)); prop_desc.is_enumerable = false; } ECMA_FINALIZE (boolean_enumerable_prop_value); ECMA_FINALIZE (enumerable_prop_value); } ecma_deref_ecma_string (enumerable_magic_string_p); if (!ecma_is_completion_value_throw (ret_value)) { JERRY_ASSERT (ecma_is_completion_value_empty (ret_value)); // 4. ecma_string_t *configurable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONFIGURABLE); if (ecma_op_object_get_property (obj_p, configurable_magic_string_p) != NULL) { ECMA_TRY_CATCH (configurable_prop_value, ecma_op_object_get (obj_p, configurable_magic_string_p), ret_value); ECMA_TRY_CATCH (boolean_configurable_prop_value, ecma_op_to_boolean (configurable_prop_value), ret_value); prop_desc.is_configurable_defined = true; if (ecma_is_value_true (boolean_configurable_prop_value)) { prop_desc.is_configurable = true; } else { JERRY_ASSERT (ecma_is_value_boolean (boolean_configurable_prop_value)); prop_desc.is_configurable = false; } ECMA_FINALIZE (boolean_configurable_prop_value); ECMA_FINALIZE (configurable_prop_value); } ecma_deref_ecma_string (configurable_magic_string_p); } if (!ecma_is_completion_value_throw (ret_value)) { JERRY_ASSERT (ecma_is_completion_value_empty (ret_value)); // 5. ecma_string_t *value_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_VALUE); if (ecma_op_object_get_property (obj_p, value_magic_string_p) != NULL) { ECMA_TRY_CATCH (value_prop_value, ecma_op_object_get (obj_p, value_magic_string_p), ret_value); prop_desc.is_value_defined = true; prop_desc.value = ecma_copy_value (value_prop_value, true); ECMA_FINALIZE (value_prop_value); } ecma_deref_ecma_string (value_magic_string_p); } if (!ecma_is_completion_value_throw (ret_value)) { JERRY_ASSERT (ecma_is_completion_value_empty (ret_value)); // 6. ecma_string_t *writable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_WRITABLE); if (ecma_op_object_get_property (obj_p, writable_magic_string_p) != NULL) { ECMA_TRY_CATCH (writable_prop_value, ecma_op_object_get (obj_p, writable_magic_string_p), ret_value); ECMA_TRY_CATCH (boolean_writable_prop_value, ecma_op_to_boolean (writable_prop_value), ret_value); prop_desc.is_writable_defined = true; if (ecma_is_value_true (boolean_writable_prop_value)) { prop_desc.is_writable = true; } else { JERRY_ASSERT (ecma_is_value_boolean (boolean_writable_prop_value)); prop_desc.is_writable = false; } ECMA_FINALIZE (boolean_writable_prop_value); ECMA_FINALIZE (writable_prop_value); } ecma_deref_ecma_string (writable_magic_string_p); } if (!ecma_is_completion_value_throw (ret_value)) { JERRY_ASSERT (ecma_is_completion_value_empty (ret_value)); // 7. ecma_string_t *get_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GET); if (ecma_op_object_get_property (obj_p, get_magic_string_p) != NULL) { ECMA_TRY_CATCH (get_prop_value, ecma_op_object_get (obj_p, get_magic_string_p), ret_value); if (!ecma_op_is_callable (get_prop_value) && !ecma_is_value_undefined (get_prop_value)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { prop_desc.is_get_defined = true; if (ecma_is_value_undefined (get_prop_value)) { prop_desc.get_p = NULL; } else { JERRY_ASSERT (ecma_is_value_object (get_prop_value)); ecma_object_t *get_p = ecma_get_object_from_value (get_prop_value); ecma_ref_object (get_p); prop_desc.get_p = get_p; } } ECMA_FINALIZE (get_prop_value); } ecma_deref_ecma_string (get_magic_string_p); } if (!ecma_is_completion_value_throw (ret_value)) { JERRY_ASSERT (ecma_is_completion_value_empty (ret_value)); // 8. ecma_string_t *set_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SET); if (ecma_op_object_get_property (obj_p, set_magic_string_p) != NULL) { ECMA_TRY_CATCH (set_prop_value, ecma_op_object_get (obj_p, set_magic_string_p), ret_value); if (!ecma_op_is_callable (set_prop_value) && !ecma_is_value_undefined (set_prop_value)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { prop_desc.is_set_defined = true; if (ecma_is_value_undefined (set_prop_value)) { prop_desc.set_p = NULL; } else { JERRY_ASSERT (ecma_is_value_object (set_prop_value)); ecma_object_t *set_p = ecma_get_object_from_value (set_prop_value); ecma_ref_object (set_p); prop_desc.set_p = set_p; } } ECMA_FINALIZE (set_prop_value); } ecma_deref_ecma_string (set_magic_string_p); } if (!ecma_is_completion_value_throw (ret_value)) { JERRY_ASSERT (ecma_is_completion_value_empty (ret_value)); // 9. if (prop_desc.is_get_defined || prop_desc.is_set_defined) { if (prop_desc.is_value_defined || prop_desc.is_writable_defined) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } } } if (!ecma_is_completion_value_throw (ret_value)) { JERRY_ASSERT (ecma_is_completion_value_empty (ret_value)); } else { ecma_free_property_descriptor (&prop_desc); } *out_prop_desc_p = prop_desc; } return ret_value; } /* ecma_op_to_property_descriptor */
/** * [[DefineOwnProperty]] ecma array object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * 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_op_array_object_define_own_property (ecma_object_t *obj_p, /**< the array object */ ecma_string_t *property_name_p, /**< property name */ const ecma_property_descriptor_t *property_desc_p, /**< property descriptor */ bool is_throw) /**< flag that controls failure handling */ { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY); // 1. ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_property_t *len_prop_p = ecma_op_object_get_own_property (obj_p, magic_string_length_p); JERRY_ASSERT (len_prop_p != NULL && len_prop_p->type == ECMA_PROPERTY_NAMEDDATA); // 2. ecma_value_t old_len_value = ecma_get_named_data_property_value (len_prop_p); ecma_number_t *num_p = ecma_get_number_from_value (old_len_value); 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); ecma_deref_ecma_string (magic_string_length_p); if (is_property_name_equal_length) { // a. if (!property_desc_p->is_value_defined) { // i. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } ecma_number_t new_len_num; // c. ecma_completion_value_t completion = ecma_op_to_number (property_desc_p->value); if (ecma_is_completion_value_throw (completion)) { return completion; } JERRY_ASSERT (ecma_is_completion_value_normal (completion) && ecma_is_value_number (ecma_get_completion_value_value (completion))); new_len_num = *ecma_get_number_from_completion_value (completion); ecma_free_completion_value (completion); uint32_t new_len_uint32 = ecma_number_to_uint32 (new_len_num); // d. if (ecma_uint32_to_number (new_len_uint32) != new_len_num) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE)); } else { // b., e. ecma_number_t *new_len_num_p = ecma_alloc_number (); *new_len_num_p = new_len_num; ecma_property_descriptor_t new_len_property_desc = *property_desc_p; new_len_property_desc.value = ecma_make_number_value (new_len_num_p); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // f. if (new_len_uint32 >= old_len_uint32) { // i. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ret_value = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); } else { // g. if (!ecma_is_property_writable (len_prop_p)) { ret_value = ecma_reject (is_throw); } else { // h. bool new_writable; if (!new_len_property_desc.is_writable_defined || new_len_property_desc.is_writable) { new_writable = true; } else { // ii. new_writable = false; // iii. new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = true; } // j. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); /* Handling normal false and throw values */ if (!ecma_is_completion_value_normal_true (succeeded)) { JERRY_ASSERT (ecma_is_completion_value_normal_false (succeeded) || ecma_is_completion_value_throw (succeeded)); // k. ret_value = succeeded; } else { // l JERRY_ASSERT (new_len_uint32 < old_len_uint32); /* * Item i. is replaced with faster iteration: only indices that actually exist in the array, are iterated */ bool is_reduce_succeeded = true; ecma_collection_header_t *array_index_props_p = ecma_op_object_get_property_names (obj_p, true, false, false); ecma_length_t array_index_props_num = array_index_props_p->unit_number; MEM_DEFINE_LOCAL_ARRAY (array_index_values_p, array_index_props_num, uint32_t); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, array_index_props_p); uint32_t array_index_values_pos = 0; while (ecma_collection_iterator_next (&iter)) { ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); uint32_t index; bool is_index = ecma_string_get_array_index (property_name_p, &index); JERRY_ASSERT (is_index); JERRY_ASSERT (index < old_len_uint32); array_index_values_p[array_index_values_pos++] = index; } JERRY_ASSERT (array_index_values_pos == array_index_props_num); while (array_index_values_pos != 0 && array_index_values_p[--array_index_values_pos] >= new_len_uint32) { uint32_t index = array_index_values_p[array_index_values_pos]; // ii. ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_completion_value_t delete_succeeded = ecma_op_object_delete (obj_p, index_string_p, false); ecma_deref_ecma_string (index_string_p); if (ecma_is_completion_value_normal_false (delete_succeeded)) { // iii. new_len_uint32 = (index + 1u); ecma_number_t *new_len_num_p = ecma_get_number_from_value (new_len_property_desc.value); // 1. *new_len_num_p = ecma_uint32_to_number (index + 1u); // 2. if (!new_writable) { new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = false; } // 3. ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_completion_value_t completion = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (completion)); is_reduce_succeeded = false; break; } } MEM_FINALIZE_LOCAL_ARRAY (array_index_values_p); ecma_free_values_collection (array_index_props_p, true); if (!is_reduce_succeeded) { ret_value = ecma_reject (is_throw); } else { // m. if (!new_writable) { ecma_property_descriptor_t prop_desc_not_writable = ecma_make_empty_property_descriptor (); prop_desc_not_writable.is_writable_defined = true; prop_desc_not_writable.is_writable = false; ecma_completion_value_t completion_set_not_writable; magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); completion_set_not_writable = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &prop_desc_not_writable, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion_set_not_writable)); } ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } } } } ecma_dealloc_number (new_len_num_p); return ret_value; } JERRY_UNREACHABLE (); } else { // 4.a. uint32_t index; if (!ecma_string_get_array_index (property_name_p, &index)) { // 5. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } // 4. // b. if (index >= old_len_uint32 && !ecma_is_property_writable (len_prop_p)) { return ecma_reject (is_throw); } // c. ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, false); // d. JERRY_ASSERT (ecma_is_completion_value_normal_true (succeeded) || ecma_is_completion_value_normal_false (succeeded)); if (ecma_is_completion_value_normal_false (succeeded)) { return ecma_reject (is_throw); } // e. if (index >= old_len_uint32) { // i., ii. ecma_number_t *num_p = ecma_alloc_number (); *num_p = ecma_number_add (ecma_uint32_to_number (index), ECMA_NUMBER_ONE); ecma_named_data_property_assign_value (obj_p, len_prop_p, ecma_make_number_value (num_p)); ecma_dealloc_number (num_p); } // f. return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } JERRY_UNREACHABLE (); } /* ecma_op_array_object_define_own_property */
/** * SetMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ ecma_completion_value_t ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ ecma_value_t value, /**< argument V */ bool is_strict) /**< argument S */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { #ifndef JERRY_NDEBUG # ifdef CONFIG_ECMA_COMPACT_PROFILE bool is_equal = false; ecma_string_t *arguments_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); if (ecma_compare_ecma_strings (name_p, arguments_magic_string_p)) { is_equal = true; } ecma_deref_ecma_string (arguments_magic_string_p); JERRY_ASSERT (!is_equal); if (is_equal) { return ecma_make_throw_obj_completion_value (ecma_builtin_get (ECMA_BUILTIN_ID_COMPACT_PROFILE_ERROR)); } # endif /* CONFIG_ECMA_COMPACT_PROFILE */ #endif /* !JERRY_NDEBUG */ ecma_property_t *property_p = ecma_get_named_data_property (lex_env_p, name_p); if (ecma_is_property_writable (property_p)) { ecma_named_data_property_assign_value (lex_env_p, property_p, value); } else if (is_strict) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_completion_value_t completion = ecma_op_object_put (binding_obj_p, name_p, value, is_strict); if (ecma_is_completion_value_throw (completion)) { return completion; } else { JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (completion)); } } return ecma_make_empty_completion_value (); } /* ecma_op_set_mutable_binding */
/** * The Function.prototype object's 'apply' routine * * See also: * ECMA-262 v5, 15.3.4.3 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_function_prototype_object_apply (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg1, /**< first argument */ ecma_value_t arg2) /**< second argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 1. */ if (!ecma_op_is_callable (this_arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *func_obj_p = ecma_get_object_from_value (this_arg); /* 2. */ if (ecma_is_value_null (arg2) || ecma_is_value_undefined (arg2)) { ret_value = ecma_op_function_call (func_obj_p, arg1, NULL); } else { /* 3. */ if (!ecma_is_value_object (arg2)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg2); ecma_string_t *length_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); /* 4. */ ECMA_TRY_CATCH (length_value, ecma_op_object_get (obj_p, length_magic_string_p), ret_value); ECMA_OP_TO_NUMBER_TRY_CATCH (length_number, length_value, ret_value); /* 5. */ const uint32_t length = ecma_number_to_uint32 (length_number); /* 6. */ ecma_collection_header_t *arg_collection_p = ecma_new_values_collection (NULL, 0, true); /* 7. */ for (uint32_t index = 0; index < length && ecma_is_completion_value_empty (ret_value); index++) { ecma_string_t *curr_idx_str_p = ecma_new_ecma_string_from_uint32 (index); ECMA_TRY_CATCH (get_value, ecma_op_object_get (obj_p, curr_idx_str_p), ret_value); ecma_append_to_values_collection (arg_collection_p, get_value, true); ECMA_FINALIZE (get_value); ecma_deref_ecma_string (curr_idx_str_p); } JERRY_ASSERT (arg_collection_p->unit_number == length || !ecma_is_completion_value_empty (ret_value)); if (ecma_is_completion_value_empty (ret_value)) { ret_value = ecma_op_function_call (func_obj_p, arg1, arg_collection_p); } ecma_free_values_collection (arg_collection_p, true); ECMA_OP_TO_NUMBER_FINALIZE (length_number); ECMA_FINALIZE (length_value); ecma_deref_ecma_string (length_magic_string_p); } } } return ret_value; } /* ecma_builtin_function_prototype_object_apply */
/** * The Function.prototype object's 'bind' routine * * See also: * ECMA-262 v5, 15.3.4.5 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this argument */ const ecma_value_t* arguments_list_p, /**< list of arguments */ ecma_length_t arguments_number) /**< number of arguments */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 2. */ if (!ecma_op_is_callable (this_arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { /* 4. 11. 18. */ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); ecma_object_t *function_p = ecma_create_object (prototype_obj_p, true, ECMA_OBJECT_TYPE_BOUND_FUNCTION); ecma_deref_object (prototype_obj_p); /* 7. */ ecma_property_t *target_function_prop_p; target_function_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION); ecma_object_t *this_arg_obj_p = ecma_get_object_from_value (this_arg); ECMA_SET_NON_NULL_POINTER (target_function_prop_p->u.internal_property.value, this_arg_obj_p); /* 8. */ ecma_property_t *bound_this_prop_p; bound_this_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS); const ecma_length_t arg_count = arguments_number; if (arg_count > 0) { bound_this_prop_p->u.internal_property.value = ecma_copy_value (arguments_list_p[0], false); } else { bound_this_prop_p->u.internal_property.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } if (arg_count > 1) { ecma_collection_header_t *bound_args_collection_p; bound_args_collection_p = ecma_new_values_collection (&arguments_list_p[1], arg_count - 1, false); ecma_property_t *bound_args_prop_p; bound_args_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS); ECMA_SET_NON_NULL_POINTER (bound_args_prop_p->u.internal_property.value, bound_args_collection_p); } /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type. * * See also: ecma_object_get_class_name */ ecma_number_t *length_p = ecma_alloc_number (); ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); /* 15. */ if (ecma_object_get_class_name (this_arg_obj_p) == LIT_MAGIC_STRING_FUNCTION_UL) { ecma_completion_value_t get_len_completion = ecma_op_object_get (this_arg_obj_p, magic_string_length_p); JERRY_ASSERT (ecma_is_completion_value_normal (get_len_completion)); ecma_value_t len_value = ecma_get_completion_value_value (get_len_completion); JERRY_ASSERT (ecma_is_value_number (len_value)); const ecma_length_t bound_arg_count = arg_count > 1 ? arg_count - 1 : 0; /* 15.a */ *length_p = *ecma_get_number_from_value (len_value) - ecma_uint32_to_number (bound_arg_count); ecma_free_completion_value (get_len_completion); /* 15.b */ if (ecma_number_is_negative (*length_p)) { *length_p = ECMA_NUMBER_ZERO; } } else { /* 16. */ *length_p = ECMA_NUMBER_ZERO; } /* 17. */ ecma_completion_value_t completion = ecma_builtin_helper_def_prop (function_p, magic_string_length_p, ecma_make_number_value (length_p), false, /* Writable */ false, /* Enumerable */ false, /* Configurable */ false); /* Failure handling */ JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (completion)); ecma_deref_ecma_string (magic_string_length_p); ecma_dealloc_number (length_p); /* 19-21. */ ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER); ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); { prop_desc.is_enumerable_defined = true; prop_desc.is_enumerable = false; prop_desc.is_configurable_defined = true; prop_desc.is_configurable = false; prop_desc.is_get_defined = true; prop_desc.get_p = thrower_p; prop_desc.is_set_defined = true; prop_desc.set_p = thrower_p; } ecma_string_t *magic_string_caller_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER); completion = ecma_op_object_define_own_property (function_p, magic_string_caller_p, &prop_desc, false); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (completion)); ecma_deref_ecma_string (magic_string_caller_p); ecma_string_t *magic_string_arguments_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); completion = ecma_op_object_define_own_property (function_p, magic_string_arguments_p, &prop_desc, false); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (completion)); ecma_deref_ecma_string (magic_string_arguments_p); ecma_deref_object (thrower_p); /* 22. */ ret_value = ecma_make_normal_completion_value (ecma_make_object_value (function_p)); } return ret_value; } /* ecma_builtin_function_prototype_object_bind */
/** * [[Call]] implementation for Function objects, * created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) * or 15.3.4.5 (ECMA_OBJECT_TYPE_BOUND_FUNCTION), * and for built-in Function objects * from section 15 (ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION). * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object */ ecma_value_t value) /**< argument 'V' */ { JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p)); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION) { if (!ecma_is_value_object (value)) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); } ecma_object_t* v_obj_p = ecma_get_object_from_value (value); ecma_string_t *prototype_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE); ECMA_TRY_CATCH (prototype_obj_value, ecma_op_object_get (func_obj_p, prototype_magic_string_p), ret_value); if (!ecma_is_value_object (prototype_obj_value)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *prototype_obj_p = ecma_get_object_from_value (prototype_obj_value); JERRY_ASSERT (prototype_obj_p != NULL); do { v_obj_p = ecma_get_object_prototype (v_obj_p); if (v_obj_p == NULL) { ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); break; } else if (v_obj_p == prototype_obj_p) { ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); break; } } while (true); } ECMA_FINALIZE (prototype_obj_value); ecma_deref_ecma_string (prototype_magic_string_p); } else if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); /* 1. */ ecma_property_t *target_function_prop_p; target_function_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION); ecma_object_t *target_func_obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, target_function_prop_p->u.internal_property.value); /* 3. */ ret_value = ecma_op_object_has_instance (target_func_obj_p, value); } return ret_value; } /* ecma_op_function_has_instance */
/** * Recursive function for RegExp matching. Tests for a regular expression * match and returns a MatchResult value. * * See also: * ECMA-262 v5, 15.10.2.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ static ecma_completion_value_t re_match_regexp (re_matcher_ctx_t *re_ctx_p, /**< RegExp matcher context */ re_bytecode_t *bc_p, /**< pointer to the current RegExp bytecode */ lit_utf8_iterator_t iter, /**< input string iterator */ lit_utf8_iterator_t *out_iter_p) /**< Output: matching substring iterator */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); re_opcode_t op; while ((op = re_get_opcode (&bc_p))) { switch (op) { case RE_OP_MATCH: { JERRY_DDLOG ("Execute RE_OP_MATCH: match\n"); *out_iter_p = iter; ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); return ret_value; /* match */ } case RE_OP_CHAR: { if (lit_utf8_iterator_is_eos (&iter)) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } bool is_ignorecase = re_ctx_p->flags & RE_FLAG_IGNORE_CASE; ecma_char_t ch1 = (ecma_char_t) re_get_value (&bc_p); /* Already canonicalized. */ ecma_char_t ch2 = re_canonicalize (lit_utf8_iterator_read_next (&iter), is_ignorecase); JERRY_DDLOG ("Character matching %d to %d: ", ch1, ch2); if (ch1 != ch2) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_PERIOD: { if (lit_utf8_iterator_is_eos (&iter)) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } ecma_char_t ch = lit_utf8_iterator_read_next (&iter); JERRY_DDLOG ("Period matching '.' to %d: ", (uint32_t) ch); if (lit_char_is_line_terminator (ch)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_ASSERT_START: { JERRY_DDLOG ("Execute RE_OP_ASSERT_START: "); if ((iter.buf_p + iter.buf_pos.offset) <= re_ctx_p->input_start_p) { JERRY_DDLOG ("match\n"); break; } if (!(re_ctx_p->flags & RE_FLAG_MULTILINE)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } if (lit_char_is_line_terminator (lit_utf8_iterator_peek_prev (&iter))) { JERRY_DDLOG ("match\n"); break; } JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_ASSERT_END: { JERRY_DDLOG ("Execute RE_OP_ASSERT_END: "); if ((iter.buf_p + iter.buf_pos.offset) >= re_ctx_p->input_end_p) { JERRY_DDLOG ("match\n"); break; /* tail merge */ } if (!(re_ctx_p->flags & RE_FLAG_MULTILINE)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } if (lit_char_is_line_terminator (lit_utf8_iterator_peek_next (&iter))) { JERRY_DDLOG ("match\n"); break; /* tail merge */ } JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_ASSERT_WORD_BOUNDARY: case RE_OP_ASSERT_NOT_WORD_BOUNDARY: { bool is_wordchar_left, is_wordchar_right; if ((iter.buf_p + iter.buf_pos.offset) <= re_ctx_p->input_start_p) { is_wordchar_left = false; /* not a wordchar */ } else { is_wordchar_left = lit_char_is_word_char (lit_utf8_iterator_peek_prev (&iter)); } if ((iter.buf_p + iter.buf_pos.offset) >= re_ctx_p->input_end_p) { is_wordchar_right = false; /* not a wordchar */ } else { is_wordchar_right = lit_char_is_word_char (lit_utf8_iterator_peek_next (&iter)); } if (op == RE_OP_ASSERT_WORD_BOUNDARY) { JERRY_DDLOG ("Execute RE_OP_ASSERT_WORD_BOUNDARY: "); if (is_wordchar_left == is_wordchar_right) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } else { JERRY_ASSERT (op == RE_OP_ASSERT_NOT_WORD_BOUNDARY); JERRY_DDLOG ("Execute RE_OP_ASSERT_NOT_WORD_BOUNDARY: "); if (is_wordchar_left != is_wordchar_right) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_LOOKAHEAD_POS: case RE_OP_LOOKAHEAD_NEG: { ecma_completion_value_t match_value = ecma_make_empty_completion_value (); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); uint32_t array_size = re_ctx_p->num_of_captures + re_ctx_p->num_of_non_captures; MEM_DEFINE_LOCAL_ARRAY (saved_bck_p, array_size, lit_utf8_iterator_t); size_t size = (size_t) (array_size) * sizeof (lit_utf8_iterator_t); memcpy (saved_bck_p, re_ctx_p->saved_p, size); do { uint32_t offset = re_get_value (&bc_p); if (!sub_iter.buf_p) { match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_completion_value_throw (match_value)) { break; } } bc_p += offset; } while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); if (!ecma_is_completion_value_throw (match_value)) { JERRY_DDLOG ("Execute RE_OP_LOOKAHEAD_POS/NEG: "); ecma_free_completion_value (match_value); if ((op == RE_OP_LOOKAHEAD_POS && sub_iter.buf_p) || (op == RE_OP_LOOKAHEAD_NEG && !sub_iter.buf_p)) { JERRY_DDLOG ("match\n"); match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); } else { JERRY_DDLOG ("fail\n"); match_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } if (!ecma_is_completion_value_throw (match_value)) { if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; } else { JERRY_ASSERT (ecma_is_value_boolean (match_value)); /* restore saved */ memcpy (re_ctx_p->saved_p, saved_bck_p, size); } } MEM_FINALIZE_LOCAL_ARRAY (saved_bck_p); return match_value; } case RE_OP_CHAR_CLASS: case RE_OP_INV_CHAR_CLASS: { uint32_t num_of_ranges; bool is_match; JERRY_DDLOG ("Execute RE_OP_CHAR_CLASS/RE_OP_INV_CHAR_CLASS, "); if (lit_utf8_iterator_is_eos (&iter)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } bool is_ignorecase = re_ctx_p->flags & RE_FLAG_IGNORE_CASE; ecma_char_t curr_ch = re_canonicalize (lit_utf8_iterator_read_next (&iter), is_ignorecase); num_of_ranges = re_get_value (&bc_p); is_match = false; while (num_of_ranges) { ecma_char_t ch1 = re_canonicalize ((ecma_char_t) re_get_value (&bc_p), is_ignorecase); ecma_char_t ch2 = re_canonicalize ((ecma_char_t) re_get_value (&bc_p), is_ignorecase); JERRY_DDLOG ("num_of_ranges=%d, ch1=%d, ch2=%d, curr_ch=%d; ", num_of_ranges, ch1, ch2, curr_ch); if (curr_ch >= ch1 && curr_ch <= ch2) { /* We must read all the ranges from bytecode. */ is_match = true; } num_of_ranges--; } if (op == RE_OP_CHAR_CLASS) { if (!is_match) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } else { JERRY_ASSERT (op == RE_OP_INV_CHAR_CLASS); if (is_match) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_BACKREFERENCE: { uint32_t backref_idx; backref_idx = re_get_value (&bc_p); JERRY_DDLOG ("Execute RE_OP_BACKREFERENCE (idx: %d): ", backref_idx); backref_idx *= 2; /* backref n -> saved indices [n*2, n*2+1] */ JERRY_ASSERT (backref_idx >= 2 && backref_idx + 1 < re_ctx_p->num_of_captures); if (!re_ctx_p->saved_p[backref_idx].buf_p || !re_ctx_p->saved_p[backref_idx + 1].buf_p) { JERRY_DDLOG ("match\n"); break; /* capture is 'undefined', always matches! */ } lit_utf8_iterator_t sub_iter = re_ctx_p->saved_p[backref_idx]; while (sub_iter.buf_pos.offset < re_ctx_p->saved_p[backref_idx + 1].buf_pos.offset) { ecma_char_t ch1, ch2; if ((iter.buf_p + iter.buf_pos.offset) >= re_ctx_p->input_end_p) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } ch1 = lit_utf8_iterator_read_next (&sub_iter); ch2 = lit_utf8_iterator_read_next (&iter); if (ch1 != ch2) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_SAVE_AT_START: { re_bytecode_t *old_bc_p; JERRY_DDLOG ("Execute RE_OP_SAVE_AT_START\n"); lit_utf8_iterator_t old_start_p = re_ctx_p->saved_p[RE_GLOBAL_START_IDX]; re_ctx_p->saved_p[RE_GLOBAL_START_IDX] = iter; do { uint32_t offset = re_get_value (&bc_p); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } bc_p += offset; old_bc_p = bc_p; } while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); bc_p = old_bc_p; re_ctx_p->saved_p[RE_GLOBAL_START_IDX] = old_start_p; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_SAVE_AND_MATCH: { JERRY_DDLOG ("End of pattern is reached: match\n"); re_ctx_p->saved_p[RE_GLOBAL_END_IDX] = iter; *out_iter_p = iter; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); /* match */ } case RE_OP_ALTERNATIVE: { /* * Alternatives should be jump over, when alternative opcode appears. */ uint32_t offset = re_get_value (&bc_p); JERRY_DDLOG ("Execute RE_OP_ALTERNATIVE"); bc_p += offset; while (*bc_p == RE_OP_ALTERNATIVE) { JERRY_DDLOG (", jump: %d"); bc_p++; offset = re_get_value (&bc_p); bc_p += offset; } JERRY_DDLOG ("\n"); break; /* tail merge */ } case RE_OP_CAPTURE_NON_GREEDY_ZERO_GROUP_START: case RE_OP_NON_CAPTURE_NON_GREEDY_ZERO_GROUP_START: { /* * On non-greedy iterations we have to execute the bytecode * after the group first, if zero iteration is allowed. */ uint32_t start_idx, iter_idx, offset; lit_utf8_iterator_t old_start = lit_utf8_iterator_create (NULL, 0); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); re_bytecode_t *old_bc_p; old_bc_p = bc_p; /* save the bytecode start position of the group start */ start_idx = re_get_value (&bc_p); offset = re_get_value (&bc_p); if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (start_idx <= re_ctx_p->num_of_captures / 2); iter_idx = start_idx - 1; start_idx *= 2; old_start = re_ctx_p->saved_p[start_idx]; re_ctx_p->saved_p[start_idx] = iter; } else { JERRY_ASSERT (start_idx < re_ctx_p->num_of_non_captures); iter_idx = start_idx + (re_ctx_p->num_of_captures / 2) - 1; start_idx += re_ctx_p->num_of_captures; } re_ctx_p->num_of_iterations_p[iter_idx] = 0; /* Jump all over to the end of the END opcode. */ bc_p += offset; /* Try to match after the close paren if zero is allowed */ ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } if (RE_IS_CAPTURE_GROUP (op)) { re_ctx_p->saved_p[start_idx] = old_start; } bc_p = old_bc_p; /* FALLTHRU */ } case RE_OP_CAPTURE_GROUP_START: case RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START: case RE_OP_NON_CAPTURE_GROUP_START: case RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START: { uint32_t start_idx, iter_idx, old_iteration_cnt, offset; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); re_bytecode_t *old_bc_p; re_bytecode_t *end_bc_p = NULL; start_idx = re_get_value (&bc_p); if (op != RE_OP_CAPTURE_GROUP_START && op != RE_OP_NON_CAPTURE_GROUP_START) { offset = re_get_value (&bc_p); end_bc_p = bc_p + offset; } if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (start_idx <= re_ctx_p->num_of_captures / 2); iter_idx = start_idx - 1; start_idx *= 2; } else { JERRY_ASSERT (start_idx < re_ctx_p->num_of_non_captures); iter_idx = start_idx + (re_ctx_p->num_of_captures / 2) - 1; start_idx += re_ctx_p->num_of_captures; } lit_utf8_iterator_t old_start = re_ctx_p->saved_p[start_idx]; old_iteration_cnt = re_ctx_p->num_of_iterations_p[iter_idx]; re_ctx_p->saved_p[start_idx] = iter; re_ctx_p->num_of_iterations_p[iter_idx] = 0; do { offset = re_get_value (&bc_p); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } bc_p += offset; old_bc_p = bc_p; } while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); bc_p = old_bc_p; re_ctx_p->num_of_iterations_p[iter_idx] = old_iteration_cnt; /* Try to match after the close paren if zero is allowed. */ if (op == RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START || op == RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START) { JERRY_ASSERT (end_bc_p); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, end_bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } } re_ctx_p->saved_p[start_idx] = old_start; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_CAPTURE_NON_GREEDY_GROUP_END: case RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END: { uint32_t end_idx, iter_idx, min, max; re_bytecode_t *old_bc_p; /* * On non-greedy iterations we have to execute the bytecode * after the group first. Try to iterate only if it fails. */ old_bc_p = bc_p; /* save the bytecode start position of the group end */ end_idx = re_get_value (&bc_p); min = re_get_value (&bc_p); max = re_get_value (&bc_p); re_get_value (&bc_p); /* start offset */ if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_captures / 2); iter_idx = end_idx - 1; end_idx = (end_idx * 2) + 1; } else { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_non_captures); iter_idx = end_idx + (re_ctx_p->num_of_captures / 2) - 1; end_idx += re_ctx_p->num_of_captures; } re_ctx_p->num_of_iterations_p[iter_idx]++; if (re_ctx_p->num_of_iterations_p[iter_idx] >= min && re_ctx_p->num_of_iterations_p[iter_idx] <= max) { lit_utf8_iterator_t old_end = re_ctx_p->saved_p[end_idx]; re_ctx_p->saved_p[end_idx] = iter; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } re_ctx_p->saved_p[end_idx] = old_end; } re_ctx_p->num_of_iterations_p[iter_idx]--; bc_p = old_bc_p; /* If non-greedy fails and try to iterate... */ /* FALLTHRU */ } case RE_OP_CAPTURE_GREEDY_GROUP_END: case RE_OP_NON_CAPTURE_GREEDY_GROUP_END: { uint32_t start_idx, end_idx, iter_idx, min, max, offset; lit_utf8_iterator_t old_start = lit_utf8_iterator_create (NULL, 0); lit_utf8_iterator_t old_end = lit_utf8_iterator_create (NULL, 0); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); re_bytecode_t *old_bc_p; end_idx = re_get_value (&bc_p); min = re_get_value (&bc_p); max = re_get_value (&bc_p); offset = re_get_value (&bc_p); if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_captures / 2); iter_idx = end_idx - 1; start_idx = end_idx * 2; end_idx = start_idx + 1; } else { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_non_captures); iter_idx = end_idx + (re_ctx_p->num_of_captures / 2) - 1; end_idx += re_ctx_p->num_of_captures; start_idx = end_idx; } /* Check the empty iteration if the minimum number of iterations is reached. */ if (re_ctx_p->num_of_iterations_p[iter_idx] >= min && iter.buf_p == re_ctx_p->saved_p[start_idx].buf_p && iter.buf_pos.offset == re_ctx_p->saved_p[start_idx].buf_pos.offset) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } re_ctx_p->num_of_iterations_p[iter_idx]++; old_bc_p = bc_p; /* Save the bytecode end position of the END opcodes for matching after it. */ old_end = re_ctx_p->saved_p[end_idx]; re_ctx_p->saved_p[end_idx] = iter; if (re_ctx_p->num_of_iterations_p[iter_idx] < max) { bc_p -= offset; offset = re_get_value (&bc_p); old_start = re_ctx_p->saved_p[start_idx]; re_ctx_p->saved_p[start_idx] = iter; ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } re_ctx_p->saved_p[start_idx] = old_start; /* Try to match alternatives if any. */ bc_p += offset; while (*bc_p == RE_OP_ALTERNATIVE) { bc_p++; /* RE_OP_ALTERNATIVE */ offset = re_get_value (&bc_p); old_start = re_ctx_p->saved_p[start_idx]; re_ctx_p->saved_p[start_idx] = iter; ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } re_ctx_p->saved_p[start_idx] = old_start; bc_p += offset; } } if (re_ctx_p->num_of_iterations_p[iter_idx] >= min && re_ctx_p->num_of_iterations_p[iter_idx] <= max) { /* Try to match the rest of the bytecode. */ ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, old_bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } } /* restore if fails */ re_ctx_p->saved_p[end_idx] = old_end; re_ctx_p->num_of_iterations_p[iter_idx]--; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_NON_GREEDY_ITERATOR: { uint32_t min, max, offset, num_of_iter; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); min = re_get_value (&bc_p); max = re_get_value (&bc_p); offset = re_get_value (&bc_p); JERRY_DDLOG ("Non-greedy iterator, min=%lu, max=%lu, offset=%ld\n", (unsigned long) min, (unsigned long) max, (long) offset); num_of_iter = 0; while (num_of_iter <= max) { if (num_of_iter >= min) { ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p + offset, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } } ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (!ecma_is_value_true (match_value)) { if (ecma_is_completion_value_throw (match_value)) { return match_value; } break; } iter = sub_iter; num_of_iter++; } return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_GREEDY_ITERATOR: { uint32_t min, max, offset, num_of_iter; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); min = re_get_value (&bc_p); max = re_get_value (&bc_p); offset = re_get_value (&bc_p); JERRY_DDLOG ("Greedy iterator, min=%lu, max=%lu, offset=%ld\n", (unsigned long) min, (unsigned long) max, (long) offset); num_of_iter = 0; while (num_of_iter < max) { ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (!ecma_is_value_true (match_value)) { if (ecma_is_completion_value_throw (match_value)) { return match_value; } break; } iter = sub_iter; num_of_iter++; } while (num_of_iter >= min) { ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p + offset, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } if (num_of_iter == min) { break; } lit_utf8_iterator_read_prev (&iter); num_of_iter--; } return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } default: { JERRY_DDLOG ("UNKNOWN opcode (%d)!\n", (uint32_t) op); return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_COMMON)); } } } JERRY_UNREACHABLE (); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } /* regexp_match */
/** * The Error.prototype object's 'toString' routine * * See also: * ECMA-262 v5, 15.11.4.4 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_error_prototype_object_to_string (ecma_value_t this_arg) /**< this argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 2. if (!ecma_is_value_object (this_arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); ecma_string_t *name_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAME); ECMA_TRY_CATCH (name_get_ret_value, ecma_op_object_get (obj_p, name_magic_string_p), ret_value); ecma_completion_value_t name_to_str_completion; if (ecma_is_value_undefined (name_get_ret_value)) { ecma_string_t *error_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ERROR_UL); name_to_str_completion = ecma_make_normal_completion_value (ecma_make_string_value (error_magic_string_p)); } else { name_to_str_completion = ecma_op_to_string (name_get_ret_value); } if (unlikely (!ecma_is_completion_value_normal (name_to_str_completion))) { ret_value = ecma_copy_completion_value (name_to_str_completion); } else { ecma_string_t *message_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE); ECMA_TRY_CATCH (msg_get_ret_value, ecma_op_object_get (obj_p, message_magic_string_p), ret_value); ecma_completion_value_t msg_to_str_completion; if (ecma_is_value_undefined (msg_get_ret_value)) { ecma_string_t *empty_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); msg_to_str_completion = ecma_make_normal_completion_value (ecma_make_string_value (empty_magic_string_p)); } else { msg_to_str_completion = ecma_op_to_string (msg_get_ret_value); } if (unlikely (!ecma_is_completion_value_normal (msg_to_str_completion))) { ret_value = ecma_copy_completion_value (msg_to_str_completion); } else { ecma_string_t *name_string_p = ecma_get_string_from_completion_value (name_to_str_completion); ecma_string_t *msg_string_p = ecma_get_string_from_completion_value (msg_to_str_completion); ecma_string_t *ret_str_p; if (ecma_string_get_length (name_string_p) == 0) { ret_str_p = ecma_copy_or_ref_ecma_string (msg_string_p); } else if (ecma_string_get_length (msg_string_p) == 0) { ret_str_p = ecma_copy_or_ref_ecma_string (name_string_p); } else { const lit_utf8_size_t size = (ecma_string_get_size (name_string_p) + ecma_string_get_size (msg_string_p) + lit_get_magic_string_size (LIT_MAGIC_STRING_COLON_CHAR) + lit_get_magic_string_size (LIT_MAGIC_STRING_SPACE_CHAR)); const ssize_t buffer_size = (ssize_t) size; ssize_t buffer_size_left = buffer_size; MEM_DEFINE_LOCAL_ARRAY (ret_str_buffer, buffer_size, lit_utf8_byte_t); lit_utf8_byte_t *ret_str_buffer_p = ret_str_buffer; ssize_t bytes = ecma_string_to_utf8_string (name_string_p, ret_str_buffer_p, buffer_size_left); JERRY_ASSERT (bytes >= 0 && buffer_size_left - bytes >= 0); buffer_size_left -= bytes; ret_str_buffer_p = ret_str_buffer + buffer_size - buffer_size_left; ret_str_buffer_p = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_COLON_CHAR, ret_str_buffer_p, buffer_size_left); buffer_size_left = buffer_size - (ret_str_buffer_p - ret_str_buffer); JERRY_ASSERT (buffer_size_left >= 0); ret_str_buffer_p = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_SPACE_CHAR, ret_str_buffer_p, buffer_size_left); buffer_size_left = buffer_size - (ret_str_buffer_p - ret_str_buffer); JERRY_ASSERT (buffer_size_left >= 0); bytes = ecma_string_to_utf8_string (msg_string_p, ret_str_buffer_p, buffer_size_left); JERRY_ASSERT (bytes >= 0 && buffer_size_left - bytes >= 0); buffer_size_left -= bytes; JERRY_ASSERT (buffer_size_left >= 0); ret_str_p = ecma_new_ecma_string_from_utf8 (ret_str_buffer, (jerry_api_size_t) (buffer_size - buffer_size_left)); MEM_FINALIZE_LOCAL_ARRAY (ret_str_buffer); } ret_value = ecma_make_normal_completion_value (ecma_make_string_value (ret_str_p)); } ecma_free_completion_value (msg_to_str_completion); ECMA_FINALIZE (msg_get_ret_value); ecma_deref_ecma_string (message_magic_string_p); } ecma_free_completion_value (name_to_str_completion); ECMA_FINALIZE (name_get_ret_value); ecma_deref_ecma_string (name_magic_string_p); } return ret_value; } /* ecma_builtin_error_prototype_object_to_string */
/** * GetBindingValue operation. * * See also: ECMA-262 v5, 10.2.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ ecma_completion_value_t ecma_op_get_binding_value (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_strict) /**< argument S */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { #ifndef JERRY_NDEBUG # ifdef CONFIG_ECMA_COMPACT_PROFILE bool is_equal = false; ecma_string_t *arguments_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); if (ecma_compare_ecma_strings (name_p, arguments_magic_string_p)) { is_equal = true; } ecma_deref_ecma_string (arguments_magic_string_p); JERRY_ASSERT (!is_equal); if (is_equal) { return ecma_make_throw_obj_completion_value (ecma_builtin_get (ECMA_BUILTIN_ID_COMPACT_PROFILE_ERROR)); } # endif /* CONFIG_ECMA_COMPACT_PROFILE */ #endif /* !JERRY_NDEBUG */ ecma_property_t *property_p = ecma_get_named_data_property (lex_env_p, name_p); ecma_value_t prop_value = ecma_get_named_data_property_value (property_p); /* is the binding mutable? */ if (!ecma_is_property_writable (property_p) && ecma_is_value_empty (prop_value)) { /* unitialized immutable binding */ if (is_strict) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_REFERENCE)); } else { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } return ecma_make_normal_completion_value (ecma_copy_value (prop_value, true)); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); if (ecma_op_object_get_property (binding_obj_p, name_p) == NULL) { if (is_strict) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_REFERENCE)); } else { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } return ecma_op_object_get (binding_obj_p, name_p); } } /* ecma_op_get_binding_value */
/** * The Object object's 'freeze' routine * * See also: * ECMA-262 v5, 15.2.3.9 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_freeze (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 1. if (!ecma_is_value_object (arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { // 2. ecma_object_t *obj_p = ecma_get_object_from_value (arg); ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, props_p); while (ecma_collection_iterator_next (&iter) && ecma_is_completion_value_empty (ret_value)) { ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); // 2.a ecma_property_descriptor_t prop_desc = ecma_get_property_descriptor_from_property (property_p); // 2.b if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_writable (property_p)) { prop_desc.is_writable = false; } // 2.c if (ecma_is_property_configurable (property_p)) { prop_desc.is_configurable = false; } // 2.d ECMA_TRY_CATCH (define_own_prop_ret, ecma_op_object_define_own_property (obj_p, property_name_p, &prop_desc, true), ret_value); ECMA_FINALIZE (define_own_prop_ret); ecma_free_property_descriptor (&prop_desc); } ecma_free_values_collection (props_p, true); if (ecma_is_completion_value_empty (ret_value)) { // 3. ecma_set_object_extensible (obj_p, false); // 4. ret_value = ecma_make_normal_completion_value (ecma_copy_value (arg, true)); } } return ret_value; } /* ecma_builtin_object_object_freeze */
/** * Array object creation operation. * * See also: ECMA-262 v5, 15.4.2.1 * ECMA-262 v5, 15.4.2.2 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_create_array_object (const 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 */ bool is_treat_single_arg_as_length) /**< if the value is true, arguments_list_len is 1 and single argument is Number, then treat the single argument as new Array's length rather than as single item of the Array */ { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); uint32_t length; const ecma_value_t *array_items_p; ecma_length_t array_items_count; if (is_treat_single_arg_as_length && arguments_list_len == 1 && ecma_is_value_number (arguments_list_p[0])) { ecma_number_t *num_p = ecma_get_number_from_value (arguments_list_p[0]); 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; } #ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ARRAY_BUILTIN ecma_object_t *array_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE); #else /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ARRAY_BUILTIN */ ecma_object_t *array_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); #endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ARRAY_BUILTIN */ ecma_object_t *obj_p = ecma_create_object (array_prototype_obj_p, true, ECMA_OBJECT_TYPE_ARRAY); ecma_deref_object (array_prototype_obj_p); /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_ARRAY type. * * See also: ecma_object_get_class_name */ ecma_string_t *length_magic_string_p = ecma_get_magic_string (LIT_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); ecma_set_named_data_property_value (length_prop_p, 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++) { if (ecma_is_value_array_hole (array_items_p[index])) { continue; } ecma_string_t *item_name_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_builtin_helper_def_prop (obj_p, item_name_string_p, array_items_p[index], true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ false); /* Failure handling */ 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 */
/** * The Object object's 'isFrozen' routine * * See also: * ECMA-262 v5, 15.2.3.12 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_is_frozen (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 1. if (!ecma_is_value_object (arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg); bool is_frozen; // 3. if (ecma_get_object_extensible (obj_p)) { is_frozen = false; } else { is_frozen = true; // 2. ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, props_p); while (ecma_collection_iterator_next (&iter)) { ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); // 2.a ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); JERRY_ASSERT (property_p->type == ECMA_PROPERTY_NAMEDDATA || property_p->type == ECMA_PROPERTY_NAMEDACCESSOR); // 2.b if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_writable (property_p)) { is_frozen = false; break; } // 2.c if (ecma_is_property_configurable (property_p)) { is_frozen = false; break; } } ecma_free_values_collection (props_p, true); } // 4. ret_value = ecma_make_simple_completion_value (is_frozen ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } return ret_value; } /* ecma_builtin_object_object_is_frozen */