/** * ImplicitThisValue 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_implicit_this_value (ecma_object_t *lex_env_p) /**< lexical environment */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); if (ecma_get_lex_env_provide_this (lex_env_p)) { ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_ref_object (binding_obj_p); return ecma_make_normal_completion_value (ecma_make_object_value (binding_obj_p)); } else { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } } /* ecma_op_implicit_this_value */
/** * The Object object's 'getPrototypeOf' routine * * See also: * ECMA-262 v5, 15.2.3.2 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_get_prototype_of (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_object_t *prototype_p = ecma_get_object_prototype (obj_p); if (prototype_p) { ret_value = ecma_make_normal_completion_value (ecma_make_object_value (prototype_p)); ecma_ref_object (prototype_p); } else { ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_NULL); } } return ret_value; } /* ecma_builtin_object_object_get_prototype_of */
/** * The Object object's 'isSealed' routine * * See also: * ECMA-262 v5, 15.2.3.11 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_is_sealed (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_sealed; // 3. if (ecma_get_object_extensible (obj_p)) { is_sealed = false; } else { /* the value can be updated in the loop below */ is_sealed = 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); // 2.b if (ecma_is_property_configurable (property_p)) { is_sealed = false; break; } } ecma_free_values_collection (props_p, true); } // 4. ret_value = ecma_make_simple_completion_value (is_sealed ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } return ret_value; } /* ecma_builtin_object_object_is_sealed */
/** * Handle calling [[Call]] of built-in Function.prototype object * * @return completion-value */ ecma_completion_value_t ecma_builtin_function_prototype_dispatch_call (const ecma_value_t* arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< number of arguments */ { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } /* ecma_builtin_function_prototype_dispatch_call */
/** * [[Get]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 8.12.3 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_general_object_get (ecma_object_t *obj_p, /**< the object */ ecma_string_t *property_name_p) /**< property name */ { JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); JERRY_ASSERT (property_name_p != NULL); // 1. const ecma_property_t *prop_p = ecma_op_object_get_property (obj_p, property_name_p); // 2. if (prop_p == NULL) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } // 3. if (prop_p->type == ECMA_PROPERTY_NAMEDDATA) { return ecma_make_normal_completion_value (ecma_copy_value (ecma_get_named_data_property_value (prop_p), true)); } else { // 4. ecma_object_t *getter_p = ecma_get_named_accessor_property_getter (prop_p); // 5. if (getter_p == NULL) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } else { return ecma_op_function_call (getter_p, ecma_make_object_value (obj_p), NULL); } } JERRY_UNREACHABLE (); } /* ecma_op_general_object_get */
/** * The Object.prototype object's 'propertyIsEnumerable' routine * * See also: * ECMA-262 v5, 15.2.4.7 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_prototype_object_property_is_enumerable (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's first argument */ { ecma_completion_value_t return_value = ecma_make_empty_completion_value (); /* 1. */ ECMA_TRY_CATCH (to_string_val, ecma_op_to_string (arg), return_value); /* 2. */ ECMA_TRY_CATCH (obj_val, ecma_op_to_object (this_arg), return_value); ecma_string_t *property_name_string_p = ecma_get_string_from_value (to_string_val); ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); /* 3. */ ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_string_p); /* 4. */ if (property_p != NULL) { bool is_enumerable = ecma_is_property_enumerable (property_p); return_value = ecma_make_simple_completion_value (is_enumerable ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } else { return_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); } ECMA_FINALIZE (obj_val); ECMA_FINALIZE (to_string_val); return return_value; } /* ecma_builtin_object_prototype_object_property_is_enumerable */
/** * Reject sequence * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_reject (bool is_throw) /**< Throw flag */ { if (is_throw) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); } } /* ecma_reject */
/** * ToBoolean operation. * * See also: * ECMA-262 v5, 9.2 * * @return completion value * Returned value is simple and so need not be freed. * However, ecma_free_completion_value may be called for it, but it is a no-op. */ ecma_completion_value_t ecma_op_to_boolean (ecma_value_t value) /**< ecma-value */ { ecma_check_value_type_is_spec_defined (value); ecma_simple_value_t ret_value; if (ecma_is_value_boolean (value)) { ret_value = (ecma_is_value_true (value) ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } else if (ecma_is_value_undefined (value) || ecma_is_value_null (value)) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else if (ecma_is_value_number (value)) { ecma_number_t *num_p = ecma_get_number_from_value (value); if (ecma_number_is_nan (*num_p) || ecma_number_is_zero (*num_p)) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else { ret_value = ECMA_SIMPLE_VALUE_TRUE; } } else if (ecma_is_value_string (value)) { ecma_string_t *str_p = ecma_get_string_from_value (value); if (ecma_string_get_length (str_p) == 0) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else { ret_value = ECMA_SIMPLE_VALUE_TRUE; } } else { JERRY_ASSERT (ecma_is_value_object (value)); ret_value = ECMA_SIMPLE_VALUE_TRUE; } return ecma_make_simple_completion_value (ret_value); } /* ecma_op_to_boolean */
/** * [[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 */
/** * The RegExp.prototype object's 'test' routine * * See also: * ECMA-262 v5, 15.10.6.3 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_regexp_prototype_test (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ECMA_TRY_CATCH (match_value, ecma_builtin_regexp_prototype_exec (this_arg, arg), ret_value); if (ecma_is_value_null (match_value)) { ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); } else { ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } ECMA_FINALIZE (match_value); return ret_value; } /* ecma_builtin_regexp_prototype_test */
/** * The Object.prototype object's 'isPrototypeOf' routine * * See also: * ECMA-262 v5, 15.2.4.6 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_prototype_object_is_prototype_of (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's first argument */ { /* 1. Is the argument an object? */ if (!ecma_is_value_object (arg)) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); } ecma_completion_value_t return_value = ecma_make_empty_completion_value (); /* 2. ToObject(this) */ ECMA_TRY_CATCH (obj_value, ecma_op_to_object (this_arg), return_value); ecma_object_t *obj_p = ecma_get_object_from_value (obj_value); /* 3. Compare prototype to object */ ECMA_TRY_CATCH (v_obj_value, ecma_op_to_object (arg), return_value); ecma_object_t *v_obj_p = ecma_get_object_from_value (v_obj_value); bool is_prototype_of = ecma_op_object_is_prototype_of (obj_p, v_obj_p); return_value = ecma_make_simple_completion_value (is_prototype_of ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); ECMA_FINALIZE (v_obj_value); ECMA_FINALIZE (obj_value); return return_value; } /* ecma_builtin_object_prototype_object_is_prototype_of */
/** * The Object object's 'getOwnPropertyDescriptor' routine * * See also: * ECMA-262 v5, 15.2.3.3 * * @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_descriptor (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)); return ret_value; } ecma_object_t *obj_p = ecma_get_object_from_value (arg1); // 2. ECMA_TRY_CATCH (name_str_value, ecma_op_to_string (arg2), ret_value); ecma_string_t *name_str_p = ecma_get_string_from_value (name_str_value); // 3. ecma_property_t *prop_p = ecma_op_object_get_own_property (obj_p, name_str_p); if (prop_p != NULL) { ecma_property_descriptor_t prop_desc = ecma_get_property_descriptor_from_property (prop_p); // 4. ecma_object_t* desc_obj_p = ecma_op_from_property_descriptor (&prop_desc); ecma_free_property_descriptor (&prop_desc); ret_value = ecma_make_normal_completion_value (ecma_make_object_value (desc_obj_p)); } else { ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } ECMA_FINALIZE (name_str_value); return ret_value; } /* ecma_builtin_object_object_get_own_property_descriptor */
/** * DeleteBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return completion value * Return value is simple and so need not be freed. * However, ecma_free_completion_value may be called for it, but it is a no-op. */ ecma_completion_value_t ecma_op_delete_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p) /**< argument N */ { 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) { ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, name_p); ecma_simple_value_t ret_val; if (prop_p == NULL) { ret_val = ECMA_SIMPLE_VALUE_TRUE; } else { JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA); if (!ecma_is_property_configurable (prop_p)) { ret_val = ECMA_SIMPLE_VALUE_FALSE; } else { ecma_delete_property (lex_env_p, prop_p); ret_val = ECMA_SIMPLE_VALUE_TRUE; } } return ecma_make_simple_completion_value (ret_val); } 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); return ecma_op_object_delete (binding_obj_p, name_p, false); } } /* ecma_op_delete_binding */
/** * 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 */
/** * GetValue operation part (object base). * * See also: ECMA-262 v5, 8.7.1, section 4 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ ecma_completion_value_t ecma_op_get_value_object_base (ecma_reference_t ref) /**< ECMA-reference */ { const ecma_value_t base = ref.base; const bool is_unresolvable_reference = ecma_is_value_undefined (base); const bool has_primitive_base = (ecma_is_value_boolean (base) || ecma_is_value_number (base) || ecma_is_value_string (base)); const bool has_object_base = (ecma_is_value_object (base) && !(ecma_is_lexical_environment (ecma_get_object_from_value (base)))); const bool is_property_reference = has_primitive_base || has_object_base; JERRY_ASSERT (!is_unresolvable_reference); JERRY_ASSERT (is_property_reference); ecma_string_t *referenced_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, ref.referenced_name_cp); // 4.a if (!has_primitive_base) { // 4.b case 1 ecma_object_t *obj_p = ecma_get_object_from_value (base); JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); return ecma_op_object_get (obj_p, referenced_name_p); } else { // 4.b case 2 ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 1. ECMA_TRY_CATCH (obj_base, ecma_op_to_object (base), ret_value); ecma_object_t *obj_p = ecma_get_object_from_value (obj_base); JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); // 2. ecma_property_t *prop_p = ecma_op_object_get_property (obj_p, referenced_name_p); if (prop_p == NULL) { // 3. ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } else if (prop_p->type == ECMA_PROPERTY_NAMEDDATA) { // 4. ecma_value_t prop_value = ecma_copy_value (ecma_get_named_data_property_value (prop_p), true); ret_value = ecma_make_normal_completion_value (prop_value); } else { // 5. JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDACCESSOR); ecma_object_t *obj_p = ecma_get_named_accessor_property_getter (prop_p); // 6. if (obj_p == NULL) { ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); } else { // 7. ret_value = ecma_op_function_call (obj_p, base, NULL, 0); } } ECMA_FINALIZE (obj_base); return ret_value; } } /* ecma_op_get_value_object_base */
/** * 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 */
/** * 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 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 */
/** * [[DefineOwnProperty]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 8.12.9 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the 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 (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); JERRY_ASSERT (property_name_p != NULL); const bool is_property_desc_generic_descriptor = (!property_desc_p->is_value_defined && !property_desc_p->is_writable_defined && !property_desc_p->is_get_defined && !property_desc_p->is_set_defined); const bool is_property_desc_data_descriptor = (property_desc_p->is_value_defined || property_desc_p->is_writable_defined); const bool is_property_desc_accessor_descriptor = (property_desc_p->is_get_defined || property_desc_p->is_set_defined); // 1. ecma_property_t *current_p = ecma_op_object_get_own_property (obj_p, property_name_p); // 2. bool extensible = ecma_get_object_extensible (obj_p); if (current_p == NULL) { // 3. if (!extensible) { return ecma_reject (is_throw); } // 4. // a. if (is_property_desc_generic_descriptor || is_property_desc_data_descriptor) { ecma_property_t *new_prop_p = ecma_create_named_data_property (obj_p, property_name_p, property_desc_p->is_writable, property_desc_p->is_enumerable, property_desc_p->is_configurable); ecma_named_data_property_assign_value (obj_p, new_prop_p, property_desc_p->value); } else { // b. JERRY_ASSERT (is_property_desc_accessor_descriptor); ecma_create_named_accessor_property (obj_p, property_name_p, property_desc_p->get_p, property_desc_p->set_p, property_desc_p->is_enumerable, property_desc_p->is_configurable); } return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } // 5. if (is_property_desc_generic_descriptor && !property_desc_p->is_enumerable_defined && !property_desc_p->is_configurable_defined) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } // 6. const bool is_current_data_descriptor = (current_p->type == ECMA_PROPERTY_NAMEDDATA); const bool is_current_accessor_descriptor = (current_p->type == ECMA_PROPERTY_NAMEDACCESSOR); JERRY_ASSERT (is_current_data_descriptor || is_current_accessor_descriptor); bool is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = true; if (property_desc_p->is_value_defined) { if (!is_current_data_descriptor || !ecma_op_same_value (property_desc_p->value, ecma_get_named_data_property_value (current_p))) { is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; } } if (property_desc_p->is_writable_defined) { if (!is_current_data_descriptor || property_desc_p->is_writable != ecma_is_property_writable (current_p)) { is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; } } if (property_desc_p->is_get_defined) { if (!is_current_accessor_descriptor || property_desc_p->get_p != ecma_get_named_accessor_property_getter (current_p)) { is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; } } if (property_desc_p->is_set_defined) { if (!is_current_accessor_descriptor || property_desc_p->set_p != ecma_get_named_accessor_property_setter (current_p)) { is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; } } if (property_desc_p->is_enumerable_defined) { if (property_desc_p->is_enumerable != ecma_is_property_enumerable (current_p)) { is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; } } if (property_desc_p->is_configurable_defined) { if (property_desc_p->is_configurable != ecma_is_property_configurable (current_p)) { is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false; } } if (is_every_field_in_desc_also_occurs_in_current_desc_with_same_value) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } // 7. if (!ecma_is_property_configurable (current_p)) { if (property_desc_p->is_configurable || (property_desc_p->is_enumerable_defined && property_desc_p->is_enumerable != ecma_is_property_enumerable (current_p))) { // a., b. return ecma_reject (is_throw); } } // 8. if (is_property_desc_generic_descriptor) { // no action required } else if (is_property_desc_data_descriptor != is_current_data_descriptor) { // 9. if (!ecma_is_property_configurable (current_p)) { // a. return ecma_reject (is_throw); } bool was_enumerable = ecma_is_property_enumerable (current_p); bool was_configurable = ecma_is_property_configurable (current_p); ecma_delete_property (obj_p, current_p); if (is_current_data_descriptor) { // b. current_p = ecma_create_named_accessor_property (obj_p, property_name_p, NULL, NULL, was_enumerable, was_configurable); } else { // c. current_p = ecma_create_named_data_property (obj_p, property_name_p, false, was_enumerable, was_configurable); } } else if (is_property_desc_data_descriptor && is_current_data_descriptor) { // 10. if (!ecma_is_property_configurable (current_p)) { // a. if (!ecma_is_property_writable (current_p)) { // i. if (property_desc_p->is_writable) { return ecma_reject (is_throw); } // ii. if (property_desc_p->is_value_defined && !ecma_op_same_value (property_desc_p->value, ecma_get_named_data_property_value (current_p))) { return ecma_reject (is_throw); } } } } else { JERRY_ASSERT (is_property_desc_accessor_descriptor && is_current_accessor_descriptor); // 11. if (!ecma_is_property_configurable (current_p)) { // a. if ((property_desc_p->is_get_defined && property_desc_p->get_p != ecma_get_named_accessor_property_getter (current_p)) || (property_desc_p->is_set_defined && property_desc_p->set_p != ecma_get_named_accessor_property_setter (current_p))) { // i., ii. return ecma_reject (is_throw); } } } // 12. if (property_desc_p->is_value_defined) { JERRY_ASSERT (current_p->type == ECMA_PROPERTY_NAMEDDATA); ecma_named_data_property_assign_value (obj_p, current_p, property_desc_p->value); } if (property_desc_p->is_writable_defined) { JERRY_ASSERT (current_p->type == ECMA_PROPERTY_NAMEDDATA); ecma_set_property_writable_attr (current_p, property_desc_p->is_writable); } if (property_desc_p->is_get_defined) { JERRY_ASSERT (current_p->type == ECMA_PROPERTY_NAMEDACCESSOR); ecma_set_named_accessor_property_getter (obj_p, current_p, property_desc_p->get_p); } if (property_desc_p->is_set_defined) { JERRY_ASSERT (current_p->type == ECMA_PROPERTY_NAMEDACCESSOR); ecma_set_named_accessor_property_setter (obj_p, current_p, property_desc_p->set_p); } if (property_desc_p->is_enumerable_defined) { ecma_set_property_enumerable_attr (current_p, property_desc_p->is_enumerable); } if (property_desc_p->is_configurable_defined) { ecma_set_property_configurable_attr (current_p, property_desc_p->is_configurable); } return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } /* ecma_op_general_object_define_own_property */
/** * [[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 */
/** * The String.prototype object's 'match' routine * * See also: * ECMA-262 v5, 15.5.4.10 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_string_prototype_object_match (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 1. */ ECMA_TRY_CATCH (this_check_coercible_value, ecma_op_check_object_coercible (this_arg), ret_value); /* 2. */ ECMA_TRY_CATCH (this_to_string_value, ecma_op_to_string (this_arg), ret_value); ecma_value_t regexp_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 3. */ if (ecma_is_value_object (arg) && ecma_object_get_class_name (ecma_get_object_from_value (arg)) == LIT_MAGIC_STRING_REGEXP_UL) { regexp_value = ecma_copy_value (arg, true); } else { /* 4. */ ecma_value_t regexp_arguments[1] = { arg }; ECMA_TRY_CATCH (new_regexp_value, ecma_builtin_regexp_dispatch_construct (regexp_arguments, 1), ret_value); regexp_value = ecma_copy_value (new_regexp_value, true); ECMA_FINALIZE (new_regexp_value); } if (ecma_is_completion_value_empty (ret_value)) { JERRY_ASSERT (!ecma_is_value_empty (regexp_value)); ecma_object_t *regexp_obj_p = ecma_get_object_from_value (regexp_value); ecma_string_t *global_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL); /* 5. */ ECMA_TRY_CATCH (global_value, ecma_op_object_get (regexp_obj_p, global_string_p), ret_value); JERRY_ASSERT (ecma_is_value_boolean (global_value)); ecma_value_t exec_arguments[1] = { this_to_string_value }; if (!ecma_is_value_true (global_value)) { /* 7. */ ret_value = ecma_builtin_regexp_prototype_dispatch_routine (LIT_MAGIC_STRING_EXEC, regexp_value, exec_arguments, 1); } else { /* 8.a. */ ecma_number_t *zero_number_p = ecma_alloc_number (); *zero_number_p = 0; ecma_string_t *index_zero_string_p = ecma_new_ecma_string_from_uint32 (0); ecma_string_t *last_index_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ECMA_TRY_CATCH (put_value, ecma_op_object_put (regexp_obj_p, last_index_string_p, ecma_make_number_value (zero_number_p), true), ret_value); /* 8.b. */ ECMA_TRY_CATCH (new_array_value, ecma_op_create_array_object (NULL, 0, false), ret_value); ecma_object_t *new_array_obj_p = ecma_get_object_from_value (new_array_value); /* 8.c. */ ecma_number_t previous_last_index = 0; /* 8.d. */ uint32_t n = 0; /* 8.e. */ bool last_match = true; //ecma_completion_value_t exec_result = ecma_make_empty_completion_value (); /* 8.f. */ while (last_match && ecma_is_completion_value_empty (ret_value)) { /* 8.f.i. */ ECMA_TRY_CATCH (exec_value, ecma_builtin_regexp_prototype_dispatch_routine (LIT_MAGIC_STRING_EXEC, regexp_value, exec_arguments, 1), ret_value); if (ecma_is_value_null (exec_value)) { /* 8.f.ii. */ last_match = false; } else { /* 8.f.iii. */ ECMA_TRY_CATCH (this_index_value, ecma_op_object_get (regexp_obj_p, last_index_string_p), ret_value); ECMA_TRY_CATCH (this_index_number, ecma_op_to_number (this_index_value), ret_value); ecma_number_t this_index = *ecma_get_number_from_value (this_index_number); /* 8.f.iii.2. */ if (this_index == previous_last_index) { ecma_number_t *new_last_index_p = ecma_alloc_number (); *new_last_index_p = this_index + 1; /* 8.f.iii.2.a. */ ECMA_TRY_CATCH (index_put_value, ecma_op_object_put (regexp_obj_p, last_index_string_p, ecma_make_number_value (new_last_index_p), true), ret_value); /* 8.f.iii.2.b. */ previous_last_index = this_index + 1; ECMA_FINALIZE (index_put_value); ecma_dealloc_number (new_last_index_p); } else { /* 8.f.iii.3. */ previous_last_index = this_index; } if (ecma_is_completion_value_empty (ret_value)) { /* 8.f.iii.4. */ JERRY_ASSERT (ecma_is_value_object (exec_value)); ecma_object_t *exec_obj_p = ecma_get_object_from_value (exec_value); ECMA_TRY_CATCH (match_string_value, ecma_op_object_get (exec_obj_p, index_zero_string_p), ret_value); /* 8.f.iii.5. */ ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); { prop_desc.is_value_defined = true; prop_desc.value = match_string_value; prop_desc.is_writable_defined = true; prop_desc.is_writable = true; prop_desc.is_enumerable_defined = true; prop_desc.is_enumerable = true; prop_desc.is_configurable_defined = true; prop_desc.is_configurable = true; } ecma_string_t *current_index_str_p = ecma_new_ecma_string_from_uint32 (n); ecma_completion_value_t completion = ecma_op_object_define_own_property (new_array_obj_p, current_index_str_p, &prop_desc, false); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion)); ecma_deref_ecma_string (current_index_str_p); /* 8.f.iii.6. */ n++; ECMA_FINALIZE (match_string_value); } ECMA_FINALIZE (this_index_number); ECMA_FINALIZE (this_index_value); } ECMA_FINALIZE (exec_value); } if (ecma_is_completion_value_empty (ret_value)) { if (n == 0) { /* 8.g. */ ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_NULL); } else { /* 8.h. */ ret_value = ecma_make_normal_completion_value (ecma_copy_value (new_array_value, true)); } } ECMA_FINALIZE (new_array_value); ECMA_FINALIZE (put_value); ecma_deref_ecma_string (last_index_string_p); ecma_deref_ecma_string (index_zero_string_p); ecma_dealloc_number (zero_number_p); } ECMA_FINALIZE (global_value); ecma_deref_ecma_string (global_string_p); ecma_free_value (regexp_value, true); } ECMA_FINALIZE (this_to_string_value); ECMA_FINALIZE (this_check_coercible_value); return ret_value; } /* ecma_builtin_string_prototype_object_match */
/** * Helper function for concatenating an ecma_value_t to an Array. * * See also: * ECMA-262 v5, 15.4.4.4 steps 5.b - 5.c * * Used by: * - The Array.prototype.concat routine. * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ ecma_completion_value_t ecma_builtin_helper_array_concat_value (ecma_object_t *obj_p, /**< array */ uint32_t *length_p, /**< in-out: array's length */ ecma_value_t value) /**< value to concat */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 5.b */ if (ecma_is_value_object (value) && (ecma_object_get_class_name (ecma_get_object_from_value (value)) == LIT_MAGIC_STRING_ARRAY_UL)) { ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); /* 5.b.ii */ ECMA_TRY_CATCH (arg_len_value, ecma_op_object_get (ecma_get_object_from_value (value), magic_string_length_p), ret_value); ECMA_OP_TO_NUMBER_TRY_CATCH (arg_len_number, arg_len_value, ret_value); uint32_t arg_len = ecma_number_to_uint32 (arg_len_number); /* 5.b.iii */ for (uint32_t array_index = 0; array_index < arg_len && ecma_is_completion_value_empty (ret_value); array_index++) { ecma_string_t *array_index_string_p = ecma_new_ecma_string_from_uint32 (array_index); /* 5.b.iii.2 */ if (ecma_op_object_get_property (ecma_get_object_from_value (value), array_index_string_p) != NULL) { ecma_string_t *new_array_index_string_p = ecma_new_ecma_string_from_uint32 (*length_p + array_index); /* 5.b.iii.3.a */ ECMA_TRY_CATCH (get_value, ecma_op_object_get (ecma_get_object_from_value (value), array_index_string_p), ret_value); ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); { prop_desc.is_value_defined = true; prop_desc.value = get_value; prop_desc.is_writable_defined = true; prop_desc.is_writable = true; prop_desc.is_enumerable_defined = true; prop_desc.is_enumerable = true; prop_desc.is_configurable_defined = true; prop_desc.is_configurable = true; } /* 5.b.iii.3.b */ /* This will always be a simple value since 'is_throw' is false, so no need to free. */ ecma_completion_value_t put_comp = ecma_op_object_define_own_property (obj_p, new_array_index_string_p, &prop_desc, false); JERRY_ASSERT (ecma_is_completion_value_normal_true (put_comp)); ECMA_FINALIZE (get_value); ecma_deref_ecma_string (new_array_index_string_p); } ecma_deref_ecma_string (array_index_string_p); } *length_p += arg_len; ECMA_OP_TO_NUMBER_FINALIZE (arg_len_number); ECMA_FINALIZE (arg_len_value); ecma_deref_ecma_string (magic_string_length_p); } else { ecma_string_t *new_array_index_string_p = ecma_new_ecma_string_from_uint32 ((*length_p)++); ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); { prop_desc.is_value_defined = true; prop_desc.value = value; prop_desc.is_writable_defined = true; prop_desc.is_writable = true; prop_desc.is_enumerable_defined = true; prop_desc.is_enumerable = true; prop_desc.is_configurable_defined = true; prop_desc.is_configurable = true; } /* 5.c.i */ /* This will always be a simple value since 'is_throw' is false, so no need to free. */ ecma_completion_value_t put_comp = ecma_op_object_define_own_property (obj_p, new_array_index_string_p, &prop_desc, false); JERRY_ASSERT (ecma_is_completion_value_normal_true (put_comp)); ecma_deref_ecma_string (new_array_index_string_p); } if (ecma_is_completion_value_empty (ret_value)) { ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } return ret_value; } /* ecma_builtin_helper_array_concat_value */
/** * [[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 */
/** * [[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 */
/** * [[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 */