/** * The Object.prototype object's 'propertyIsEnumerable' routine * * See also: * ECMA-262 v5, 15.2.4.7 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_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_value_t return_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 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 = ecma_op_object_get_own_property (obj_p, property_name_string_p, NULL, ECMA_PROPERTY_GET_NO_OPTIONS); /* 4. */ if (property != ECMA_PROPERTY_TYPE_NOT_FOUND) { bool is_enumerable = ecma_is_property_enumerable (property); return_value = ecma_make_boolean_value (is_enumerable); } else { return_value = ecma_make_simple_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 */
/** * 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 */
/** * Construct property descriptor from specified property * * @return property descriptor, corresponding to type and content of the specified property, i.e.: * - for named data properties: { [Value], [Writable], [Enumerable], [Configurable] }; * - for named accessor properties: { [Get] - if defined, * [Set] - if defined, * [Enumerable], [Configurable] * }. */ ecma_property_descriptor_t ecma_get_property_descriptor_from_property (ecma_property_t *prop_p) /**< property */ { ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); prop_desc.is_enumerable = ecma_is_property_enumerable (prop_p); prop_desc.is_enumerable_defined = true; prop_desc.is_configurable = ecma_is_property_configurable (prop_p); prop_desc.is_configurable_defined = true; if (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA) { prop_desc.value = ecma_copy_value (ecma_get_named_data_property_value (prop_p)); prop_desc.is_value_defined = true; prop_desc.is_writable = ecma_is_property_writable (prop_p); prop_desc.is_writable_defined = true; } else { JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); prop_desc.get_p = ecma_get_named_accessor_property_getter (prop_p); prop_desc.is_get_defined = true; if (prop_desc.get_p != NULL) { ecma_ref_object (prop_desc.get_p); } prop_desc.set_p = ecma_get_named_accessor_property_setter (prop_p); prop_desc.is_set_defined = true; if (prop_desc.set_p != NULL) { ecma_ref_object (prop_desc.set_p); } } return prop_desc; } /* ecma_get_property_descriptor_from_property */
/** * The Object.keys and Object.getOwnPropertyName routine's common part. * * See also: * ECMA-262 v5, 15.2.3.4 steps 2-5 * ECMA-262 v5, 15.2.3.14 steps 3-6 * * @return completion value - Array of property names. * Returned value must be freed with ecma_free_completion_value. */ ecma_completion_value_t ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /** < object */ bool only_enumerable_properties) /** < list enumerable properties? */ { JERRY_ASSERT (obj_p != NULL); ecma_completion_value_t new_array = ecma_op_create_array_object (NULL, 0, false); JERRY_ASSERT (ecma_is_completion_value_normal (new_array)); ecma_object_t *new_array_p = ecma_get_object_from_completion_value (new_array); uint32_t index = 0; for (ecma_property_t *property_p = ecma_get_property_list (obj_p); property_p != NULL; property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p)) { ecma_string_t *property_name_p; if (property_p->type == ECMA_PROPERTY_NAMEDDATA) { property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, property_p->u.named_data_property.name_p); } else if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR) { property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, property_p->u.named_accessor_property.name_p); } else { continue; } if (only_enumerable_properties && !ecma_is_property_enumerable (property_p)) { continue; } JERRY_ASSERT (property_name_p != NULL); ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_property_descriptor_t item_prop_desc = ecma_make_empty_property_descriptor (); { item_prop_desc.is_value_defined = true; item_prop_desc.value = ecma_make_string_value (property_name_p); item_prop_desc.is_writable_defined = true; item_prop_desc.is_writable = true; item_prop_desc.is_enumerable_defined = true; item_prop_desc.is_enumerable = true; item_prop_desc.is_configurable_defined = true; item_prop_desc.is_configurable = true; } ecma_completion_value_t completion = ecma_op_object_define_own_property (new_array_p, index_string_p, &item_prop_desc, false); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion)); ecma_free_completion_value (completion); ecma_deref_ecma_string (index_string_p); index++; } return new_array; } /* ecma_builtin_helper_object_get_properties */
/** * Enumerate properties and construct collection with their * names for further iteration in for-in opcode handler. * * See also: * ECMA-262 v5, 12.6.4 * * @return header of constructed strings collection (should be freed with ecma_free_values_collection), * or NULL - if there are no properties to enumerate in for-in. */ static ecma_collection_header_t * vm_helper_for_in_enumerate_properties_names (ecma_object_t *obj_p) /**< starting object - result of ToObject * conversion (ECMA-262 v5, 12.6.4, step 4) */ { const size_t bitmap_row_size = sizeof (uint32_t) * JERRY_BITSINBYTE; uint32_t names_hashes_bitmap[(1u << LIT_STRING_HASH_BITS) / bitmap_row_size]; memset (names_hashes_bitmap, 0, sizeof (names_hashes_bitmap)); ecma_length_t all_properties_count = 0; /* First pass: counting properties */ for (ecma_object_t *prototype_chain_iter_p = obj_p; prototype_chain_iter_p != NULL; prototype_chain_iter_p = ecma_get_object_prototype (prototype_chain_iter_p)) { for (ecma_property_t *prop_iter_p = ecma_get_property_list (prototype_chain_iter_p); prop_iter_p != NULL; prop_iter_p = ECMA_GET_POINTER (ecma_property_t, prop_iter_p->next_property_p)) { if (prop_iter_p->type == ECMA_PROPERTY_NAMEDDATA || prop_iter_p->type == ECMA_PROPERTY_NAMEDACCESSOR) { all_properties_count++; } else { JERRY_ASSERT (prop_iter_p->type == ECMA_PROPERTY_INTERNAL); } } } if (all_properties_count == 0) { return NULL; } ecma_collection_header_t *ret_p = NULL; /* Second pass: collecting properties names */ MEM_DEFINE_LOCAL_ARRAY (names_p, all_properties_count, ecma_string_t*); ecma_length_t enumerated_properties_count = 0; ecma_length_t non_enumerated_properties_count = 0; for (ecma_object_t *prototype_chain_iter_p = obj_p; prototype_chain_iter_p != NULL; prototype_chain_iter_p = ecma_get_object_prototype (prototype_chain_iter_p)) { for (ecma_property_t *prop_iter_p = ecma_get_property_list (prototype_chain_iter_p); prop_iter_p != NULL; prop_iter_p = ECMA_GET_POINTER (ecma_property_t, prop_iter_p->next_property_p)) { if (prop_iter_p->type == ECMA_PROPERTY_NAMEDDATA || prop_iter_p->type == ECMA_PROPERTY_NAMEDACCESSOR) { bool is_enumerated; ecma_string_t *prop_name_p; if (prop_iter_p->type == ECMA_PROPERTY_NAMEDDATA) { prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_iter_p->u.named_data_property.name_p); } else { prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_iter_p->u.named_accessor_property.name_p); } lit_string_hash_t hash = prop_name_p->hash; uint32_t bitmap_row = hash / bitmap_row_size; uint32_t bitmap_column = hash % bitmap_row_size; if (ecma_is_property_enumerable (prop_iter_p)) { if ((names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) == 0) { /* no name with the hash occured during the iteration session */ is_enumerated = true; } else { /* name with same hash already occured */ bool is_equal_found = false; for (uint32_t index = 0; !is_equal_found && index < enumerated_properties_count; index++) { if (ecma_compare_ecma_strings (prop_name_p, names_p[index])) { is_equal_found = true; } } for (uint32_t index = 0; !is_equal_found && index < non_enumerated_properties_count; index++) { if (ecma_compare_ecma_strings (prop_name_p, names_p[all_properties_count - index - 1])) { is_equal_found = true; } } is_enumerated = !is_equal_found; } } else { is_enumerated = false; } names_hashes_bitmap[bitmap_row] |= (1u << bitmap_column); if (is_enumerated) { names_p[enumerated_properties_count++] = prop_name_p; } else { names_p[all_properties_count - non_enumerated_properties_count++ - 1] = prop_name_p; } JERRY_ASSERT (enumerated_properties_count + non_enumerated_properties_count <= all_properties_count); } else { JERRY_ASSERT (prop_iter_p->type == ECMA_PROPERTY_INTERNAL); } } } if (enumerated_properties_count != 0) { ret_p = ecma_new_strings_collection (names_p, enumerated_properties_count); } MEM_FINALIZE_LOCAL_ARRAY (names_p); return ret_p; } /* vm_helper_for_in_enumerate_properties_names */
/** * [[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 */
/** * Abstract operation 'JO' defined in 15.12.3 * * See also: * ECMA-262 v5, 15.12.3 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_json_stringify_context_t *context_p) /**< context*/ { ecma_value_t obj_value = ecma_make_object_value (obj_p); /* 1. */ if (ecma_has_object_value_in_collection (context_p->occurence_stack_p, obj_value)) { return ecma_raise_type_error (""); } ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 2. */ ecma_append_to_values_collection (context_p->occurence_stack_p, obj_value, true); /* 3. */ ecma_string_t *stepback_p = context_p->indent_str_p; /* 4. */ context_p->indent_str_p = ecma_concat_ecma_strings (context_p->indent_str_p, context_p->gap_str_p); ecma_collection_header_t *property_keys_p; /* 5. */ if (context_p->property_list_p->unit_number > 0) { property_keys_p = context_p->property_list_p; } /* 6. */ else { property_keys_p = ecma_new_values_collection (NULL, 0, true); ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, true, 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); ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); JERRY_ASSERT (ecma_is_property_enumerable (property_p)); if (property_p->type == ECMA_PROPERTY_NAMEDDATA) { ecma_append_to_values_collection (property_keys_p, *iter.current_value_p, true); } } ecma_free_values_collection (props_p, true); } /* 7. */ ecma_collection_header_t *partial_p = ecma_new_values_collection (NULL, 0, true); /* 8. */ ecma_collection_iterator_t iterator; ecma_collection_iterator_init (&iterator, property_keys_p); while (ecma_collection_iterator_next (&iterator) && ecma_is_value_empty (ret_value)) { ecma_value_t value = *iterator.current_value_p; ecma_string_t *key_p = ecma_get_string_from_value (value); /* 8.a */ ECMA_TRY_CATCH (str_val, ecma_builtin_json_str (key_p, obj_p, context_p), ret_value); /* 8.b */ if (!ecma_is_value_undefined (str_val)) { ecma_string_t *colon_p = ecma_get_magic_string (LIT_MAGIC_STRING_COLON_CHAR); ecma_string_t *value_str_p = ecma_get_string_from_value (str_val); ecma_string_t *tmp_str_p; /* 8.b.i */ ecma_value_t str_comp_val = ecma_builtin_json_quote (key_p); JERRY_ASSERT (!ecma_is_value_error (str_comp_val)); ecma_string_t *member_str_p = ecma_get_string_from_value (str_comp_val); /* 8.b.ii */ tmp_str_p = ecma_concat_ecma_strings (member_str_p, colon_p); ecma_free_value (str_comp_val); ecma_deref_ecma_string (colon_p); member_str_p = tmp_str_p; /* 8.b.iii */ bool is_gap_empty = (ecma_string_get_length (context_p->gap_str_p) == 0); if (!is_gap_empty) { ecma_string_t *space_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_SPACE_CHAR); tmp_str_p = ecma_concat_ecma_strings (member_str_p, space_str_p); ecma_deref_ecma_string (member_str_p); ecma_deref_ecma_string (space_str_p); member_str_p = tmp_str_p; } /* 8.b.iv */ tmp_str_p = ecma_concat_ecma_strings (member_str_p, value_str_p); ecma_deref_ecma_string (member_str_p); member_str_p = tmp_str_p; /* 8.b.v */ ecma_value_t member_value = ecma_make_string_value (member_str_p); ecma_append_to_values_collection (partial_p, member_value, true); ecma_deref_ecma_string (member_str_p); } ECMA_FINALIZE (str_val); } if (context_p->property_list_p->unit_number == 0) { ecma_free_values_collection (property_keys_p, true); } if (!ecma_is_value_empty (ret_value)) { ecma_free_values_collection (partial_p, true); ecma_deref_ecma_string (stepback_p); return ret_value; } /* 9. */ if (partial_p->unit_number == 0) { ecma_string_t *left_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_BRACE_CHAR); ecma_string_t *right_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR); ecma_string_t *final_str_p = ecma_concat_ecma_strings (left_brace_str_p, right_brace_str_p); ret_value = ecma_make_string_value (final_str_p); ecma_deref_ecma_string (left_brace_str_p); ecma_deref_ecma_string (right_brace_str_p); } /* 10. */ else { bool is_gap_empty = (ecma_string_get_length (context_p->gap_str_p) == 0); /* 10.a */ if (is_gap_empty) { ecma_string_t *left_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_BRACE_CHAR); ecma_string_t *right_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR); ret_value = ecma_builtin_helper_json_create_non_formatted_json (left_brace_str_p, right_brace_str_p, partial_p); ecma_deref_ecma_string (left_brace_str_p); ecma_deref_ecma_string (right_brace_str_p); } /* 10.b */ else { ecma_string_t *left_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_BRACE_CHAR); ecma_string_t *right_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR); ret_value = ecma_builtin_helper_json_create_formatted_json (left_brace_str_p, right_brace_str_p, stepback_p, partial_p, context_p); ecma_deref_ecma_string (left_brace_str_p); ecma_deref_ecma_string (right_brace_str_p); } } ecma_free_values_collection (partial_p, true); /* 11. */ ecma_remove_last_value_from_values_collection (context_p->occurence_stack_p); /* 12. */ ecma_deref_ecma_string (context_p->indent_str_p); context_p->indent_str_p = stepback_p; /* 13. */ return ret_value; } /* ecma_builtin_json_object */
/** * [[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 */