/** * CreateIterResultObject operation * * See also: * ECMA-262 v6, 7.4.7. * * Note: * Returned value must be freed with ecma_free_value. * * @return iterator result object */ ecma_value_t ecma_create_iter_result_object (ecma_value_t value, /**< value */ ecma_value_t done) /**< ECMA_VALUE_{TRUE,FALSE} based * on the iterator index */ { /* 1. */ JERRY_ASSERT (ecma_is_value_boolean (done)); /* 2. */ ecma_object_t *object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), 0, ECMA_OBJECT_TYPE_GENERAL); /* 3. */ ecma_property_value_t *prop_value_p; prop_value_p = ecma_create_named_data_property (object_p, ecma_get_magic_string (LIT_MAGIC_STRING_VALUE), ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL); prop_value_p->value = ecma_copy_value_if_not_object (value); /* 4. */ prop_value_p = ecma_create_named_data_property (object_p, ecma_get_magic_string (LIT_MAGIC_STRING_DONE), ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL); prop_value_p->value = done; /* 5. */ return ecma_make_object_value (object_p); } /* ecma_create_iter_result_object */
/** * CreateMutableBinding 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_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_deletable) /**< argument D */ { 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_create_named_data_property (lex_env_p, name_p, true, false, is_deletable); } 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_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); { prop_desc.is_value_defined = true; prop_desc.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); 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 = is_deletable; } ecma_completion_value_t completion = ecma_op_object_define_own_property (binding_obj_p, name_p, &prop_desc, true); 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_create_mutable_binding */
/** * CreateMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_deletable) /**< argument D */ { 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) { uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE; if (is_deletable) { prop_attributes = (uint8_t) (prop_attributes | ECMA_PROPERTY_FLAG_CONFIGURABLE); } ecma_create_named_data_property (lex_env_p, name_p, prop_attributes, NULL); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_value_t completion; if (!ecma_get_object_extensible (binding_obj_p)) { return ECMA_VALUE_EMPTY; } completion = ecma_builtin_helper_def_prop (binding_obj_p, name_p, ECMA_VALUE_UNDEFINED, is_deletable ? ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE : ECMA_PROPERTY_ENUMERABLE_WRITABLE, true); /* Failure handling */ if (ECMA_IS_VALUE_ERROR (completion)) { return completion; } else { JERRY_ASSERT (ecma_is_value_boolean (completion)); } } return ECMA_VALUE_EMPTY; } /* ecma_op_create_mutable_binding */
/** * Construct a Function object for specified built-in routine * * See also: ECMA-262 v5, 15 * * @return pointer to constructed Function object */ ecma_object_t* ecma_builtin_make_function_object_for_routine (ecma_builtin_id_t builtin_id, /**< identifier of built-in object that initially contains property with the routine */ uint16_t routine_id, /**< builtin-wide identifier of the built-in object's routine property */ ecma_number_t length_prop_num_value) /**< ecma-number - value of 'length' property of function object to create */ { ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); ecma_object_t *func_obj_p = ecma_create_object (prototype_obj_p, true, ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION); ecma_deref_object (prototype_obj_p); ecma_set_object_is_builtin (func_obj_p, true); uint64_t packed_value = jrt_set_bit_field_value (0, builtin_id, ECMA_BUILTIN_ROUTINE_ID_BUILT_IN_OBJECT_ID_POS, ECMA_BUILTIN_ROUTINE_ID_BUILT_IN_OBJECT_ID_WIDTH); packed_value = jrt_set_bit_field_value (packed_value, routine_id, ECMA_BUILTIN_ROUTINE_ID_BUILT_IN_ROUTINE_ID_POS, ECMA_BUILTIN_ROUTINE_ID_BUILT_IN_ROUTINE_ID_WIDTH); ecma_property_t *routine_id_prop_p = ecma_create_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_ID); JERRY_ASSERT ((uint32_t) packed_value == packed_value); routine_id_prop_p->u.internal_property.value = (uint32_t) packed_value; ecma_string_t* magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_property_t *len_prop_p = ecma_create_named_data_property (func_obj_p, magic_string_length_p, false, false, false); ecma_deref_ecma_string (magic_string_length_p); ecma_number_t* len_p = ecma_alloc_number (); *len_p = length_prop_num_value; ecma_set_named_data_property_value (len_prop_p, ecma_make_number_value (len_p)); return func_obj_p; } /* ecma_builtin_make_function_object_for_routine */
/** * Standard ecma-error object constructor. * * @return pointer to ecma-object representing specified error * with reference counter set to one. */ ecma_object_t * ecma_new_standard_error_with_message (ecma_standard_error_t error_type, /**< native error type */ ecma_string_t *message_string_p) /**< message string */ { ecma_object_t *new_error_obj_p = ecma_new_standard_error (error_type); ecma_string_t *message_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE); ecma_property_t *prop_p = ecma_create_named_data_property (new_error_obj_p, message_magic_string_p, ECMA_PROPERTY_CONFIGURABLE_WRITABLE); ecma_ref_ecma_string (message_string_p); ecma_set_named_data_property_value (prop_p, ecma_make_string_value (message_string_p)); ecma_deref_ecma_string (message_magic_string_p); return new_error_obj_p; } /* ecma_new_standard_error_with_message */
/** * CreateMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_deletable) /**< argument D */ { 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_create_named_data_property (lex_env_p, name_p, true, false, is_deletable); } 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_value_t completion; completion = ecma_builtin_helper_def_prop (binding_obj_p, name_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), true, /* Writable */ true, /* Enumerable */ is_deletable, /* Configurable */ true); /* Failure handling */ if (ecma_is_value_error (completion)) { return completion; } else { JERRY_ASSERT (ecma_is_value_boolean (completion)); } } return ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); } /* ecma_op_create_mutable_binding */
/** * CreateImmutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 */ void ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ ecma_value_t value) /**< argument V */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); /* * Warning: * Whether immutable bindings are deletable seems not to be defined by ECMA v5. */ ecma_property_value_t *prop_value_p = ecma_create_named_data_property (lex_env_p, name_p, ECMA_PROPERTY_FIXED, NULL); prop_value_p->value = ecma_copy_value_if_not_object (value); } /* ecma_op_create_immutable_binding */
/** * CreateImmutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 */ void ecma_op_create_immutable_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 (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); /* * Warning: * Whether immutable bindings are deletable seems not to be defined by ECMA v5. */ ecma_property_t *prop_p = ecma_create_named_data_property (lex_env_p, name_p, false, false, false); JERRY_ASSERT (ecma_is_value_undefined (ecma_get_named_data_property_value (prop_p))); ecma_set_named_data_property_value (prop_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY)); } /* ecma_op_create_immutable_binding */
/** * [[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 */
/** * Get backtrace. The backtrace is an array of strings where * each string contains the position of the corresponding frame. * The array length is zero if the backtrace is not available. * * @return array ecma value */ ecma_value_t vm_get_backtrace (uint32_t max_depth) /**< maximum backtrace depth, 0 = unlimited */ { #ifdef JERRY_ENABLE_LINE_INFO ecma_value_t result_array = ecma_op_create_array_object (NULL, 0, false); if (max_depth == 0) { max_depth = UINT32_MAX; } vm_frame_ctx_t *context_p = JERRY_CONTEXT (vm_top_context_p); ecma_object_t *array_p = ecma_get_object_from_value (result_array); uint32_t index = 0; while (context_p != NULL) { if (context_p->resource_name == ECMA_VALUE_UNDEFINED) { context_p = context_p->prev_context_p; continue; } ecma_string_t *str_p = ecma_get_string_from_value (context_p->resource_name); if (ecma_string_is_empty (str_p)) { const char *unknown_str_p = "<unknown>:"; str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) unknown_str_p, (lit_utf8_size_t) strlen (unknown_str_p)); } else { ecma_ref_ecma_string (str_p); str_p = ecma_append_magic_string_to_string (str_p, LIT_MAGIC_STRING_COLON_CHAR); } ecma_string_t *line_str_p = ecma_new_ecma_string_from_uint32 (context_p->current_line); str_p = ecma_concat_ecma_strings (str_p, line_str_p); ecma_deref_ecma_string (line_str_p); ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); ecma_property_value_t *prop_value_p; prop_value_p = ecma_create_named_data_property (array_p, index_str_p, ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL); ecma_deref_ecma_string (index_str_p); prop_value_p->value = ecma_make_string_value (str_p); context_p = context_p->prev_context_p; index++; if (index >= max_depth) { break; } } if (index > 0) { JERRY_ASSERT (ecma_get_object_type (array_p) == ECMA_OBJECT_TYPE_ARRAY); ((ecma_extended_object_t *) array_p)->u.array.length = index; } return result_array; #else /* !JERRY_ENABLE_LINE_INFO */ JERRY_UNUSED (max_depth); return ecma_op_create_array_object (NULL, 0, false); #endif /* JERRY_ENABLE_LINE_INFO */ } /* vm_get_backtrace */
/** * The JSON object's 'parse' routine * * See also: * ECMA-262 v5, 15.12.2 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_json_parse (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg1, /**< string argument */ ecma_value_t arg2) /**< reviver argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (string, ecma_op_to_string (arg1), ret_value); ecma_string_t *string_p = ecma_get_string_from_value (string); ecma_length_t string_size = (uint32_t) ecma_string_get_size (string_p); size_t buffer_size = sizeof (lit_utf8_byte_t) * (string_size + 1); MEM_DEFINE_LOCAL_ARRAY (str_start_p, buffer_size, lit_utf8_byte_t); ssize_t sz = ecma_string_to_utf8_string (string_p, str_start_p, (ssize_t) buffer_size); JERRY_ASSERT (sz == (ssize_t) string_size); str_start_p[string_size] = LIT_BYTE_NULL; ecma_json_token_t token; token.current_p = str_start_p; token.end_p = str_start_p + string_size; ecma_value_t final_result = ecma_builtin_json_parse_value (&token); if (!ecma_is_value_undefined (final_result)) { ecma_builtin_json_parse_next_token (&token); if (token.type != end_token) { ecma_free_value (final_result); final_result = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } if (ecma_is_value_undefined (final_result)) { ret_value = ecma_raise_syntax_error (""); } else { if (ecma_op_is_callable (arg2)) { ecma_object_t *object_p = ecma_op_create_object_object_noarg (); ecma_string_t *name_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); ecma_property_t *property_p = ecma_create_named_data_property (object_p, name_p, true, true, true); ecma_named_data_property_assign_value (object_p, property_p, final_result); ecma_free_value (final_result); ret_value = ecma_builtin_json_walk (ecma_get_object_from_value (arg2), object_p, name_p); ecma_deref_object (object_p); ecma_deref_ecma_string (name_p); } else { ret_value = final_result; } } MEM_FINALIZE_LOCAL_ARRAY (str_start_p); ECMA_FINALIZE (string); return ret_value; } /* ecma_builtin_json_parse */
/* * Initializes the source, global, ignoreCase, multiline, and lastIndex properties of RegExp instance. */ void re_initialize_props (ecma_object_t *re_obj_p, /**< RegExp obejct */ ecma_string_t *source_p, /**< source string */ uint8_t flags) /**< flags */ { /* Set source property. ECMA-262 v5, 15.10.7.1 */ ecma_string_t *magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE); ecma_property_t *prop_p = ecma_find_named_property (re_obj_p, magic_string_p); if (prop_p == NULL) { prop_p = ecma_create_named_data_property (re_obj_p, magic_string_p, false, false, false); } ecma_deref_ecma_string (magic_string_p); JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA); ecma_named_data_property_assign_value (re_obj_p, prop_p, ecma_make_string_value (source_p)); ecma_simple_value_t prop_value; /* Set global property. ECMA-262 v5, 15.10.7.2 */ magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL); prop_p = ecma_find_named_property (re_obj_p, magic_string_p); if (prop_p == NULL) { prop_p = ecma_create_named_data_property (re_obj_p, magic_string_p, false, false, false); } ecma_deref_ecma_string (magic_string_p); prop_value = flags & RE_FLAG_GLOBAL ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE; JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA); ecma_set_named_data_property_value (prop_p, ecma_make_simple_value (prop_value)); /* Set ignoreCase property. ECMA-262 v5, 15.10.7.3 */ magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL); prop_p = ecma_find_named_property (re_obj_p, magic_string_p); if (prop_p == NULL) { prop_p = ecma_create_named_data_property (re_obj_p, magic_string_p, false, false, false); } ecma_deref_ecma_string (magic_string_p); prop_value = flags & RE_FLAG_IGNORE_CASE ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE; JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA); ecma_set_named_data_property_value (prop_p, ecma_make_simple_value (prop_value)); /* Set multiline property. ECMA-262 v5, 15.10.7.4 */ magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE); prop_p = ecma_find_named_property (re_obj_p, magic_string_p); if (prop_p == NULL) { prop_p = ecma_create_named_data_property (re_obj_p, magic_string_p, false, false, false); } ecma_deref_ecma_string (magic_string_p); prop_value = flags & RE_FLAG_MULTILINE ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE; JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA); ecma_set_named_data_property_value (prop_p, ecma_make_simple_value (prop_value)); /* Set lastIndex property. ECMA-262 v5, 15.10.7.5 */ magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); prop_p = ecma_find_named_property (re_obj_p, magic_string_p); if (prop_p == NULL) { prop_p = ecma_create_named_data_property (re_obj_p, magic_string_p, true, false, false); } ecma_deref_ecma_string (magic_string_p); ecma_number_t *lastindex_num_p = ecma_alloc_number (); *lastindex_num_p = ECMA_NUMBER_ZERO; JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA); ecma_named_data_property_assign_value (re_obj_p, prop_p, ecma_make_number_value (lastindex_num_p)); ecma_dealloc_number (lastindex_num_p); } /* re_initialize_props */
/** * Lazy instantation of non-builtin ecma function object's properties * * Warning: * Only non-configurable properties could be instantiated lazily in this function, * as configurable properties could be deleted and it would be incorrect * to reinstantiate them in the function in second time. * * @return pointer to newly instantiated property, if a property was instantiated, * NULL - otherwise */ ecma_property_t * ecma_op_function_try_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */ ecma_string_t *property_name_p) /**< property name */ { static const char prototype_str_p[] = "prototype"; JERRY_ASSERT (!ecma_get_object_is_builtin (object_p)); ecma_string_container_t container = ECMA_STRING_GET_CONTAINER (property_name_p); /* Check whether the property_name_p is prototype */ if (container == ECMA_STRING_CONTAINER_MAGIC_STRING) { if (property_name_p->u.magic_string_id != LIT_MAGIC_STRING_PROTOTYPE) { return NULL; } } else if (container != ECMA_STRING_CONTAINER_HEAP_UTF8_STRING || property_name_p->u.utf8_string.size != (sizeof (prototype_str_p) - 1)) { return NULL; } else { if (strncmp ((char *) (property_name_p + 1), prototype_str_p, (sizeof (prototype_str_p) - 1)) != 0) { return NULL; } } /* ECMA-262 v5, 13.2, 16-18 */ /* 16. */ ecma_object_t *proto_object_p = ecma_op_create_object_object_noarg (); /* 17. */ ecma_string_t *magic_string_constructor_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR); ecma_property_value_t *constructor_prop_value_p; constructor_prop_value_p = ecma_create_named_data_property (proto_object_p, magic_string_constructor_p, ECMA_PROPERTY_CONFIGURABLE_WRITABLE, NULL); constructor_prop_value_p->value = ecma_make_object_value (object_p); ecma_deref_ecma_string (magic_string_constructor_p); /* 18. */ ecma_property_t *prototype_prop_p; ecma_property_value_t *prototype_prop_value_p; prototype_prop_value_p = ecma_create_named_data_property (object_p, property_name_p, ECMA_PROPERTY_FLAG_WRITABLE, &prototype_prop_p); prototype_prop_value_p->value = ecma_make_object_value (proto_object_p); ecma_deref_object (proto_object_p); return prototype_prop_p; } /* ecma_op_function_try_lazy_instantiate_property */
/** * String object creation operation. * * See also: ECMA-262 v5, 15.5.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_create_string_object (const ecma_value_t *arguments_list_p, /**< list of arguments that are passed to String constructor */ ecma_length_t arguments_list_len) /**< length of the arguments' list */ { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); ecma_string_t *prim_prop_str_value_p; ecma_number_t length_value; if (arguments_list_len == 0) { prim_prop_str_value_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING__EMPTY); length_value = ECMA_NUMBER_ZERO; } else { ecma_value_t to_str_arg_value = ecma_op_to_string (arguments_list_p[0]); if (ECMA_IS_VALUE_ERROR (to_str_arg_value)) { return to_str_arg_value; } else { JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (to_str_arg_value)); JERRY_ASSERT (ecma_is_value_string (to_str_arg_value)); prim_prop_str_value_p = ecma_get_string_from_value (to_str_arg_value); ecma_length_t string_len = ecma_string_get_length (prim_prop_str_value_p); length_value = ((ecma_number_t) (uint32_t) string_len); } } #ifndef CONFIG_DISABLE_STRING_BUILTIN ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_STRING_PROTOTYPE); #else /* CONFIG_DISABLE_STRING_BUILTIN */ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); #endif /* !CONFIG_DISABLE_STRING_BUILTIN */ ecma_object_t *obj_p = ecma_create_object (prototype_obj_p, false, true, ECMA_OBJECT_TYPE_STRING); ecma_deref_object (prototype_obj_p); /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_STRING type. * * See also: ecma_object_get_class_name */ ecma_property_t *prim_value_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_ECMA_VALUE); ecma_set_internal_property_value (prim_value_prop_p, ecma_make_string_value (prim_prop_str_value_p)); // 15.5.5.1 ecma_string_t *length_magic_string_p = ecma_new_ecma_length_string (); ecma_property_t *length_prop_p = ecma_create_named_data_property (obj_p, length_magic_string_p, ECMA_PROPERTY_FIXED); ecma_set_named_data_property_value (length_prop_p, ecma_make_number_value (length_value)); ecma_deref_ecma_string (length_magic_string_p); return ecma_make_object_value (obj_p); } /* ecma_op_create_string_object */
/** * [[GetOwnProperty]] ecma String object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 15.5.5.2 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_property_t * ecma_op_string_object_get_own_property (ecma_object_t *obj_p, /**< a String object */ ecma_string_t *property_name_p) /**< property name */ { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_STRING); // 1. ecma_property_t *prop_p = ecma_op_general_object_get_own_property (obj_p, property_name_p); // 2. if (prop_p != NULL) { return prop_p; } // 3., 5. uint32_t uint32_index; ecma_string_t *new_prop_name_p; if (ECMA_STRING_GET_CONTAINER (property_name_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC) { uint32_index = property_name_p->u.uint32_number; new_prop_name_p = property_name_p; ecma_ref_ecma_string (new_prop_name_p); } else { ecma_number_t index = ecma_string_to_number (property_name_p); uint32_index = ecma_number_to_uint32 (index); ecma_string_t *to_str_p = ecma_new_ecma_string_from_uint32 (uint32_index); bool are_equal = ecma_compare_ecma_strings (to_str_p, property_name_p); if (!are_equal) { ecma_deref_ecma_string (to_str_p); return NULL; } else { new_prop_name_p = to_str_p; } } // 4. ecma_property_t *prim_value_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_ECMA_VALUE); ecma_string_t *prim_value_str_p; prim_value_str_p = ecma_get_string_from_value (ecma_get_internal_property_value (prim_value_prop_p)); // 6. ecma_length_t length = ecma_string_get_length (prim_value_str_p); ecma_property_t *new_prop_p; if (uint32_index >= (uint32_t) length) { // 7. new_prop_p = NULL; } else { // 8. ecma_char_t c = ecma_string_get_char_at_pos (prim_value_str_p, uint32_index); // 9. ecma_string_t *new_prop_str_value_p = ecma_new_ecma_string_from_code_unit (c); new_prop_p = ecma_create_named_data_property (obj_p, new_prop_name_p, ECMA_PROPERTY_FLAG_ENUMERABLE); ecma_set_named_data_property_value (new_prop_p, ecma_make_string_value (new_prop_str_value_p)); } ecma_deref_ecma_string (new_prop_name_p); return new_prop_p; } /* ecma_op_string_object_get_own_property */
/** * If the property's name is one of built-in properties of the object * that is not instantiated yet, instantiate the property and * return pointer to the instantiated property. * * @return pointer property, if one was instantiated, * NULL - otherwise. */ ecma_property_t * ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object */ ecma_string_t *string_p) /**< property's name */ { JERRY_ASSERT (ecma_get_object_is_builtin (object_p)); const ecma_object_type_t type = ecma_get_object_type (object_p); if (type == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION) { ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); bool is_length_property = ecma_compare_ecma_strings (string_p, magic_string_length_p); ecma_deref_ecma_string (magic_string_length_p); if (is_length_property) { /* * Lazy instantiation of 'length' property * * Note: * We don't need to mark that the property was already lazy instantiated, * as it is non-configurable and so can't be deleted */ ecma_property_t *desc_prop_p = ecma_get_internal_property (object_p, ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_DESC); uint64_t builtin_routine_desc = desc_prop_p->u.internal_property.value; JERRY_STATIC_ASSERT (sizeof (uint8_t) * JERRY_BITSINBYTE == ECMA_BUILTIN_ROUTINE_ID_LENGTH_VALUE_WIDTH, bits_in_uint8_t_must_be_equal_to_ECMA_BUILTIN_ROUTINE_ID_LENGTH_VALUE_WIDTH); uint8_t length_prop_value = (uint8_t) jrt_extract_bit_field (builtin_routine_desc, ECMA_BUILTIN_ROUTINE_ID_LENGTH_VALUE_POS, ECMA_BUILTIN_ROUTINE_ID_LENGTH_VALUE_WIDTH); ecma_property_t *len_prop_p = ecma_create_named_data_property (object_p, string_p, false, false, false); ecma_number_t *len_p = ecma_alloc_number (); *len_p = length_prop_value; ecma_set_named_data_property_value (len_prop_p, ecma_make_number_value (len_p)); JERRY_ASSERT (!ecma_is_property_configurable (len_prop_p)); return len_prop_p; } return NULL; } else { ecma_property_t *built_in_id_prop_p = ecma_get_internal_property (object_p, ECMA_INTERNAL_PROPERTY_BUILT_IN_ID); ecma_builtin_id_t builtin_id = (ecma_builtin_id_t) built_in_id_prop_p->u.internal_property.value; JERRY_ASSERT (ecma_builtin_is (object_p, builtin_id)); switch (builtin_id) { #define BUILTIN(builtin_id, \ object_type, \ object_prototype_builtin_id, \ is_extensible, \ is_static, \ lowercase_name) \ case builtin_id: \ { \ return ecma_builtin_ ## lowercase_name ## _try_to_instantiate_property (object_p, \ string_p); \ } #include "ecma-builtins.inc.h" case ECMA_BUILTIN_ID__COUNT: { JERRY_UNREACHABLE (); } default: { #ifdef CONFIG_ECMA_COMPACT_PROFILE JERRY_UNREACHABLE (); #else /* CONFIG_ECMA_COMPACT_PROFILE */ JERRY_UNIMPLEMENTED ("The built-in is not implemented."); #endif /* !CONFIG_ECMA_COMPACT_PROFILE */ } } JERRY_UNREACHABLE (); } } /* ecma_builtin_try_to_instantiate_property */
/** * [[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 ecma value * Returned value must be freed with ecma_free_value */ ecma_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); ecma_property_types_t property_desc_type = ECMA_PROPERTY_TYPE_GENERIC; if (property_desc_p->is_value_defined || property_desc_p->is_writable_defined) { /* A property descriptor cannot be both named data and named accessor. */ JERRY_ASSERT (!property_desc_p->is_get_defined && !property_desc_p->is_set_defined); property_desc_type = ECMA_PROPERTY_TYPE_NAMEDDATA; } else if (property_desc_p->is_get_defined || property_desc_p->is_set_defined) { property_desc_type = ECMA_PROPERTY_TYPE_NAMEDACCESSOR; } /* These three asserts ensures that a new property is created with the appropriate default flags. * E.g. if is_configurable_defined is false, the newly created property must be non-configurable. */ JERRY_ASSERT (property_desc_p->is_configurable_defined || !property_desc_p->is_configurable); JERRY_ASSERT (property_desc_p->is_enumerable_defined || !property_desc_p->is_enumerable); JERRY_ASSERT (property_desc_p->is_writable_defined || !property_desc_p->is_writable); // 1. ecma_property_t *current_p = ecma_op_object_get_own_property (obj_p, property_name_p); if (current_p == NULL) { // 3. if (!ecma_get_object_extensible (obj_p)) { // 2. return ecma_reject (is_throw); } // 4. if (property_desc_type != ECMA_PROPERTY_TYPE_NAMEDACCESSOR) { // a. JERRY_ASSERT (property_desc_type == ECMA_PROPERTY_TYPE_GENERIC || property_desc_type == ECMA_PROPERTY_TYPE_NAMEDDATA); 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); JERRY_ASSERT (property_desc_p->is_value_defined || ecma_is_value_undefined (property_desc_p->value)); ecma_named_data_property_assign_value (obj_p, new_prop_p, property_desc_p->value); } else { // b. 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_value (ECMA_SIMPLE_VALUE_TRUE); } // 6. ecma_property_types_t current_property_type = ECMA_PROPERTY_GET_TYPE (current_p); const bool is_current_configurable = ecma_is_property_configurable (current_p); JERRY_ASSERT (current_property_type == ECMA_PROPERTY_TYPE_NAMEDDATA || current_property_type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); // 7. a., b. if (!is_current_configurable && (property_desc_p->is_configurable || (property_desc_p->is_enumerable_defined && (property_desc_p->is_enumerable != ecma_is_property_enumerable (current_p))))) { return ecma_reject (is_throw); } // 8. if (property_desc_type == ECMA_PROPERTY_TYPE_GENERIC) { /* No action required. */ } else if (likely (property_desc_type == current_property_type)) { /* If property is configurable, there is no need for checks. */ if (unlikely (!is_current_configurable)) { if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDDATA) { // 10. a. i. & ii. if (!ecma_is_property_writable (current_p) && (property_desc_p->is_writable || (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 { // 11. // 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); } } } } else { // 9. if (!is_current_configurable) { // a. return ecma_reject (is_throw); } /* The following implementation can be optimized by directly overwriting * the fields of current_p if this code path is performance critical. */ bool was_enumerable = ecma_is_property_enumerable (current_p); ecma_delete_property (obj_p, current_p); if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR) { // b. current_p = ecma_create_named_accessor_property (obj_p, property_name_p, NULL, NULL, was_enumerable, true); } else { // c. current_p = ecma_create_named_data_property (obj_p, property_name_p, false, was_enumerable, true); } } // 12. if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDDATA) { JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (current_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); if (property_desc_p->is_value_defined) { ecma_named_data_property_assign_value (obj_p, current_p, property_desc_p->value); } if (property_desc_p->is_writable_defined) { ecma_set_property_writable_attr (current_p, property_desc_p->is_writable); } } else if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR) { JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (current_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); if (property_desc_p->is_get_defined) { ecma_set_named_accessor_property_getter (obj_p, current_p, property_desc_p->get_p); } if (property_desc_p->is_set_defined) { 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_value (ECMA_SIMPLE_VALUE_TRUE); } /* ecma_op_general_object_define_own_property */
/** * Array object creation operation. * * See also: ECMA-262 v5, 15.4.2.1 * ECMA-262 v5, 15.4.2.2 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_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 = ecma_get_number_from_value (arguments_list_p[0]); uint32_t num_uint32 = ecma_number_to_uint32 (num); if (num != ((ecma_number_t) num_uint32)) { return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid array length.")); } 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_DISABLE_ARRAY_BUILTIN ecma_object_t *array_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE); #else /* CONFIG_DISABLE_ARRAY_BUILTIN */ ecma_object_t *array_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); #endif /* !CONFIG_DISABLE_ARRAY_BUILTIN */ ecma_object_t *obj_p = ecma_create_object (array_prototype_obj_p, 0, 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_new_ecma_length_string (); ecma_property_value_t *length_prop_value_p; length_prop_value_p = ecma_create_named_data_property (obj_p, length_magic_string_p, ECMA_PROPERTY_FLAG_WRITABLE, NULL); length_prop_value_p->value = ecma_make_number_value ((ecma_number_t) length); 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_object_value (obj_p); } /* ecma_op_create_array_object */
/** * If the property's name is one of built-in properties of the object * that is not instantiated yet, instantiate the property and * return pointer to the instantiated property. * * @return pointer property, if one was instantiated, * NULL - otherwise. */ ecma_property_t * ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object */ ecma_string_t *string_p) /**< property's name */ { JERRY_ASSERT (ecma_get_object_is_builtin (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION && ecma_builtin_function_is_routine (object_p)) { if (ecma_string_is_length (string_p)) { /* * Lazy instantiation of 'length' property * * Note: * We don't need to mark that the property was already lazy instantiated, * as it is non-configurable and so can't be deleted */ ecma_property_t *len_prop_p = ecma_create_named_data_property (object_p, string_p, ECMA_PROPERTY_FIXED); ecma_set_named_data_property_value (len_prop_p, ecma_make_integer_value (ext_obj_p->u.built_in.length)); JERRY_ASSERT (!ecma_is_property_configurable (len_prop_p)); return len_prop_p; } return NULL; } lit_magic_string_id_t magic_string_id; if (!ecma_is_string_magic (string_p, &magic_string_id)) { return NULL; } ecma_builtin_id_t builtin_id = (ecma_builtin_id_t) ext_obj_p->u.built_in.id; JERRY_ASSERT (builtin_id < ECMA_BUILTIN_ID__COUNT); JERRY_ASSERT (ecma_builtin_is (object_p, builtin_id)); const ecma_builtin_property_descriptor_t *property_list_p = ecma_builtin_property_list_references[builtin_id]; const ecma_builtin_property_descriptor_t *curr_property_p = property_list_p; while (curr_property_p->magic_string_id != magic_string_id) { if (curr_property_p->magic_string_id == LIT_MAGIC_STRING__COUNT) { return NULL; } curr_property_p++; } uint32_t index = (uint32_t) (curr_property_p - property_list_p); JERRY_ASSERT (index < 64); if (likely (index < 32)) { uint32_t bit_for_index = (uint32_t) 1u << index; if (ext_obj_p->u.built_in.instantiated_bitset & bit_for_index) { /* This property was instantiated before. */ return NULL; } ext_obj_p->u.built_in.instantiated_bitset |= bit_for_index; } else { uint32_t bit_for_index = (uint32_t) 1u << (index - 32); ecma_value_t *mask_prop_p = ecma_find_internal_property (object_p, ECMA_INTERNAL_PROPERTY_INSTANTIATED_MASK_32_63); uint32_t instantiated_bitset; if (mask_prop_p == NULL) { mask_prop_p = ecma_create_internal_property (object_p, ECMA_INTERNAL_PROPERTY_INSTANTIATED_MASK_32_63); instantiated_bitset = 0; } else { instantiated_bitset = *mask_prop_p; if (instantiated_bitset & bit_for_index) { /* This property was instantiated before. */ return NULL; } } *mask_prop_p = (instantiated_bitset | bit_for_index); } ecma_value_t value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); switch (curr_property_p->type) { case ECMA_BUILTIN_PROPERTY_SIMPLE: { value = ecma_make_simple_value (curr_property_p->value); break; } case ECMA_BUILTIN_PROPERTY_NUMBER: { ecma_number_t num = 0.0; if (curr_property_p->value < ECMA_BUILTIN_NUMBER_MAX) { num = curr_property_p->value; } else if (curr_property_p->value < ECMA_BUILTIN_NUMBER_NAN) { static const ecma_number_t builtin_number_list[] = { ECMA_NUMBER_MAX_VALUE, ECMA_NUMBER_MIN_VALUE, ECMA_NUMBER_E, ECMA_NUMBER_PI, ECMA_NUMBER_LN10, ECMA_NUMBER_LN2, ECMA_NUMBER_LOG2E, ECMA_NUMBER_LOG10E, ECMA_NUMBER_SQRT2, ECMA_NUMBER_SQRT_1_2 }; num = builtin_number_list[curr_property_p->value - ECMA_BUILTIN_NUMBER_MAX]; } else { switch (curr_property_p->value) { case ECMA_BUILTIN_NUMBER_NAN: { num = ecma_number_make_nan (); break; } case ECMA_BUILTIN_NUMBER_POSITIVE_INFINITY: { num = ecma_number_make_infinity (false); break; } case ECMA_BUILTIN_NUMBER_NEGATIVE_INFINITY: { num = ecma_number_make_infinity (true); break; } default: { JERRY_UNREACHABLE (); break; } } } value = ecma_make_number_value (num); break; } case ECMA_BUILTIN_PROPERTY_STRING: { value = ecma_make_string_value (ecma_get_magic_string (curr_property_p->value)); break; } case ECMA_BUILTIN_PROPERTY_OBJECT: { value = ecma_make_object_value (ecma_builtin_get (curr_property_p->value)); break; } case ECMA_BUILTIN_PROPERTY_ROUTINE: { ecma_object_t *func_obj_p; func_obj_p = ecma_builtin_make_function_object_for_routine (builtin_id, ECMA_GET_ROUTINE_ID (curr_property_p->value), ECMA_GET_ROUTINE_LENGTH (curr_property_p->value)); value = ecma_make_object_value (func_obj_p); break; } default: { JERRY_UNREACHABLE (); return NULL; } } ecma_property_t *prop_p = ecma_create_named_data_property (object_p, string_p, curr_property_p->attributes); ecma_set_named_data_property_value (prop_p, value); /* Reference count of objects must be decreased. */ if (ecma_is_value_object (value)) { ecma_free_value (value); } return prop_p; } /* ecma_builtin_try_to_instantiate_property */
/** * Initialize specified built-in object. * * @return pointer to the object */ static ecma_object_t * ecma_builtin_init_object (ecma_builtin_id_t obj_builtin_id, /**< built-in ID */ ecma_object_t *prototype_obj_p, /**< prototype object */ ecma_object_type_t obj_type, /**< object's type */ bool is_extensible) /**< value of object's [[Extensible]] property */ { ecma_object_t *obj_p = ecma_create_object (prototype_obj_p, true, is_extensible, obj_type); /* * [[Class]] property of built-in object is not stored explicitly. * * See also: ecma_object_get_class_name */ ecma_set_object_is_builtin (obj_p); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; ext_obj_p->u.built_in.id = obj_builtin_id; ext_obj_p->u.built_in.routine_id = obj_builtin_id; ext_obj_p->u.built_in.instantiated_bitset = 0; /** Initializing [[PrimitiveValue]] properties of built-in prototype objects */ switch (obj_builtin_id) { #ifndef CONFIG_DISABLE_ARRAY_BUILTIN case ECMA_BUILTIN_ID_ARRAY_PROTOTYPE: { ecma_string_t *length_str_p = ecma_new_ecma_length_string (); ecma_property_t *length_prop_p = ecma_create_named_data_property (obj_p, length_str_p, ECMA_PROPERTY_FLAG_WRITABLE); ecma_set_named_data_property_value (length_prop_p, ecma_make_integer_value (0)); ecma_deref_ecma_string (length_str_p); break; } #endif /* !CONFIG_DISABLE_ARRAY_BUILTIN */ #ifndef CONFIG_DISABLE_STRING_BUILTIN case ECMA_BUILTIN_ID_STRING_PROTOTYPE: { ecma_string_t *prim_prop_str_value_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); ecma_value_t *prim_value_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_ECMA_VALUE); *prim_value_p = ecma_make_string_value (prim_prop_str_value_p); break; } #endif /* !CONFIG_DISABLE_STRING_BUILTIN */ #ifndef CONFIG_DISABLE_NUMBER_BUILTIN case ECMA_BUILTIN_ID_NUMBER_PROTOTYPE: { ecma_value_t *prim_value_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_ECMA_VALUE); *prim_value_p = ecma_make_integer_value (0); break; } #endif /* !CONFIG_DISABLE_NUMBER_BUILTIN */ #ifndef CONFIG_DISABLE_BOOLEAN_BUILTIN case ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE: { ecma_value_t *prim_value_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_ECMA_VALUE); *prim_value_p = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); break; } #endif /* !CONFIG_DISABLE_BOOLEAN_BUILTIN */ #ifndef CONFIG_DISABLE_DATE_BUILTIN case ECMA_BUILTIN_ID_DATE_PROTOTYPE: { ecma_number_t *prim_prop_num_value_p = ecma_alloc_number (); *prim_prop_num_value_p = ecma_number_make_nan (); ecma_value_t *prim_value_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_DATE_FLOAT); ECMA_SET_INTERNAL_VALUE_POINTER (*prim_value_p, prim_prop_num_value_p); break; } #endif /* !CONFIG_DISABLE_DATE_BUILTIN */ #ifndef CONFIG_DISABLE_REGEXP_BUILTIN case ECMA_BUILTIN_ID_REGEXP_PROTOTYPE: { ecma_value_t *bytecode_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); *bytecode_prop_p = ECMA_NULL_POINTER; break; } #endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ default: { break; } } return obj_p; } /* ecma_builtin_init_object */
/** * 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 */
/** * [[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 * Also incorporates [[CanPut]] ECMA-262 v5, 8.12.4 * * @return ecma value * The returned value must be freed with ecma_free_value. * * Returns with ECMA_SIMPLE_VALUE_TRUE if the operation is * successful. Otherwise it returns with an error object * or ECMA_SIMPLE_VALUE_FALSE. * * Note: even if is_throw is false, the setter can throw an * error, and this function returns with that error. */ ecma_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); ecma_object_t *setter_p = NULL; ecma_property_t *prop_p = ecma_op_object_get_own_property (obj_p, property_name_p); if (prop_p != NULL) { if (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA) { if (ecma_is_property_writable (prop_p)) { const ecma_object_type_t type = ecma_get_object_type (obj_p); if (type == ECMA_OBJECT_TYPE_ARGUMENTS || (type == ECMA_OBJECT_TYPE_ARRAY && ecma_op_general_object_property_name_is_length (property_name_p))) { /* These cases cannot be optimized. */ ecma_property_descriptor_t value_desc = ecma_make_empty_property_descriptor (); value_desc.is_value_defined = true; value_desc.value = value; return ecma_op_object_define_own_property (obj_p, property_name_p, &value_desc, is_throw); } /* There is no need for special casing arrays here because changing the * value of an existing property never changes the length of an array. */ ecma_named_data_property_assign_value (obj_p, prop_p, value); return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); } } else { JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); setter_p = ecma_get_named_accessor_property_setter (prop_p); } } else { ecma_object_t *proto_p = ecma_get_object_prototype (obj_p); bool create_new_property = true; if (proto_p != NULL) { ecma_property_t *inherited_prop_p = ecma_op_object_get_property (proto_p, property_name_p); if (inherited_prop_p != NULL) { if (ECMA_PROPERTY_GET_TYPE (inherited_prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR) { setter_p = ecma_get_named_accessor_property_setter (inherited_prop_p); create_new_property = false; } else { create_new_property = ecma_is_property_writable (inherited_prop_p); } } } if (create_new_property && ecma_get_object_extensible (obj_p)) { const ecma_object_type_t type = ecma_get_object_type (obj_p); if (type == ECMA_OBJECT_TYPE_ARGUMENTS) { return ecma_builtin_helper_def_prop (obj_p, property_name_p, value, true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ is_throw); /* Failure handling */ } uint32_t index; if (type == ECMA_OBJECT_TYPE_ARRAY && ecma_string_get_array_index (property_name_p, &index)) { /* Since the length of an array is a non-configurable named data * property, the prop_p must be a non-NULL pointer for all arrays. */ JERRY_ASSERT (!ecma_op_general_object_property_name_is_length (property_name_p)); 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); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (len_prop_p != NULL && ECMA_PROPERTY_GET_TYPE (len_prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); uint32_t old_len = ecma_get_uint32_from_value (ecma_get_named_data_property_value (len_prop_p)); if (index < UINT32_MAX && index >= old_len) { if (!ecma_is_property_writable (len_prop_p)) { return ecma_reject (is_throw); } ecma_property_value_t *len_prop_value_p = ECMA_PROPERTY_VALUE_PTR (len_prop_p); ecma_value_assign_uint32 (&len_prop_value_p->value, index + 1); } } ecma_property_t *new_prop_p = ecma_create_named_data_property (obj_p, property_name_p, true, /* Writable */ true, /* Enumerable */ true); /* Configurable */ JERRY_ASSERT (ecma_is_value_undefined (ecma_get_named_data_property_value (new_prop_p))); ecma_set_named_data_property_value (new_prop_p, ecma_copy_value_if_not_object (value)); return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); } } if (setter_p == NULL) { return ecma_reject (is_throw); } ecma_value_t ret_value = ecma_op_function_call (setter_p, ecma_make_object_value (obj_p), &value, 1); if (!ecma_is_value_error (ret_value)) { ecma_fast_free_value (ret_value); ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); } return ret_value; } /* ecma_op_general_object_put */