/** * [[GetProperty]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 8.12.2 * * @return pointer to a property - if it exists, * NULL (i.e. ecma-undefined) - otherwise. */ ecma_property_t* ecma_op_general_object_get_property (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. ecma_property_t *prop_p = ecma_op_object_get_own_property (obj_p, property_name_p); // 2. if (prop_p != NULL) { return prop_p; } // 3. ecma_object_t *prototype_p = ecma_get_object_prototype (obj_p); // 4., 5. if (prototype_p != NULL) { return ecma_op_object_get_property (prototype_p, property_name_p); } else { return NULL; } } /* ecma_op_general_object_get_property */
/** * 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 */
/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p); if (lex_env_p != NULL) { ecma_gc_set_object_visited (lex_env_p, true); } if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); ecma_gc_set_object_visited (binding_object_p, true); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } } if (traverse_properties) { ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); if (prop_iter_p->types[0].type_and_flags != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 0); } if (prop_iter_p->types[1].type_and_flags != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 1); } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } } } /* ecma_gc_mark */
/** * Object's isPrototypeOf operation * * See also: * ECMA-262 v5, 15.2.4.6; 3 * * @return true if the target object is prototype of the base object * false if the target object is not prototype of the base object */ bool ecma_op_object_is_prototype_of (ecma_object_t *base_p, /** < base object */ ecma_object_t *target_p) /** < target object */ { do { target_p = ecma_get_object_prototype (target_p); if (target_p == NULL) { return false; } else if (target_p == base_p) { return true; } } while (true); } /* ecma_op_object_is_prototype_of */
/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p); if (lex_env_p != NULL) { ecma_gc_set_object_visited (lex_env_p, true); } if (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND) { ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); ecma_gc_set_object_visited (binding_object_p, true); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } } if (traverse_properties) { for (ecma_property_t *property_p = ecma_get_property_list (object_p), *next_property_p; property_p != NULL; property_p = next_property_p) { next_property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p); switch ((ecma_property_type_t) property_p->type) { case ECMA_PROPERTY_NAMEDDATA: { ecma_value_t value = ecma_get_named_data_property_value (property_p); if (ecma_is_value_object (value)) { ecma_object_t *value_obj_p = ecma_get_object_from_value (value); ecma_gc_set_object_visited (value_obj_p, true); } break; } case ECMA_PROPERTY_NAMEDACCESSOR: { ecma_object_t *getter_obj_p = ecma_get_named_accessor_property_getter (property_p); ecma_object_t *setter_obj_p = ecma_get_named_accessor_property_setter (property_p); if (getter_obj_p != NULL) { ecma_gc_set_object_visited (getter_obj_p, true); } if (setter_obj_p != NULL) { ecma_gc_set_object_visited (setter_obj_p, true); } break; } case ECMA_PROPERTY_INTERNAL: { ecma_internal_property_id_t property_id = (ecma_internal_property_id_t) property_p->u.internal_property.type; uint32_t property_value = property_p->u.internal_property.value; switch (property_id) { case ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES: /* a collection of ecma-values */ case ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES: /* a collection of ecma-values */ { JERRY_UNIMPLEMENTED ("Indexed array storage is not implemented yet."); } case ECMA_INTERNAL_PROPERTY_PROTOTYPE: /* the property's value is located in ecma_object_t (see above in the routine) */ case ECMA_INTERNAL_PROPERTY_EXTENSIBLE: /* the property's value is located in ecma_object_t (see above in the routine) */ case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type, * but number of the real internal property types */ { JERRY_UNREACHABLE (); } case ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS: /* a collection of strings */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE: /* compressed pointer to a ecma_string_t */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE: /* compressed pointer to a ecma_number_t */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE: /* a simple boolean value */ case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */ case ECMA_INTERNAL_PROPERTY_CODE_BYTECODE: /* compressed pointer to a bytecode array */ case ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET: /* an integer */ case ECMA_INTERNAL_PROPERTY_NATIVE_CODE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_FREE_CALLBACK: /* an object's native free callback */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_DESC: /* an integer */ case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_0_31: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_32_63: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS: { break; } case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */ case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */ { ecma_object_t *obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, property_value); ecma_gc_set_object_visited (obj_p, true); break; } } break; } } } } } /* ecma_gc_mark */
/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p); if (lex_env_p != NULL) { ecma_gc_set_object_visited (lex_env_p, true); } if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); ecma_gc_set_object_visited (binding_object_p, true); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } if (!ecma_get_object_is_builtin (object_p) && ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION) { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ext_func_p->u.function.scope_cp); ecma_gc_set_object_visited (scope_p, true); } } if (traverse_properties) { ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); if (prop_iter_p != NULL && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_HASHMAP) { prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); if (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 0); } if (prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 1); } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } } } /* ecma_gc_mark */
/** * 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 */
/** * [[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_FUNCTION). * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_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_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION) { if (ecma_get_object_is_builtin (func_obj_p) && ecma_builtin_function_is_routine (func_obj_p)) { return ecma_raise_type_error (ECMA_ERR_MSG ("Function parameter cannot be built-in a function.")); } if (!ecma_is_value_object (value)) { return ecma_make_simple_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_raise_type_error (ECMA_ERR_MSG ("Expected an object.")); } 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_value (ECMA_SIMPLE_VALUE_FALSE); break; } else if (v_obj_p == prototype_obj_p) { ret_value = ecma_make_simple_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_EXTERNAL_FUNCTION) { ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Expected a function.")); } else { JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); /* 1. */ ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p; ecma_object_t *target_func_obj_p; target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ext_function_p->u.bound_function.target_function); /* 3. */ ret_value = ecma_op_object_has_instance (target_func_obj_p, value); } return ret_value; } /* ecma_op_function_has_instance */
/* * Converts an standard error into a string. * * @return standard error string */ static ecma_string_t * jerry_debugger_exception_object_to_string (ecma_value_t exception_obj_value) /**< exception object */ { ecma_object_t *object_p = ecma_get_object_from_value (exception_obj_value); ecma_object_t *prototype_p = ecma_get_object_prototype (object_p); if (prototype_p == NULL || ecma_get_object_type (prototype_p) != ECMA_OBJECT_TYPE_GENERAL || !ecma_get_object_is_builtin (prototype_p)) { return NULL; } lit_magic_string_id_t string_id; switch (((ecma_extended_object_t *) prototype_p)->u.built_in.id) { #ifndef CONFIG_DISABLE_ERROR_BUILTINS case ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE: { string_id = LIT_MAGIC_STRING_EVAL_ERROR_UL; break; } case ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE: { string_id = LIT_MAGIC_STRING_RANGE_ERROR_UL; break; } case ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE: { string_id = LIT_MAGIC_STRING_REFERENCE_ERROR_UL; break; } case ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE: { string_id = LIT_MAGIC_STRING_SYNTAX_ERROR_UL; break; } case ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE: { string_id = LIT_MAGIC_STRING_TYPE_ERROR_UL; break; } case ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE: { string_id = LIT_MAGIC_STRING_URI_ERROR_UL; break; } #endif /* !CONFIG_DISABLE_ERROR_BUILTINS */ case ECMA_BUILTIN_ID_ERROR_PROTOTYPE: { string_id = LIT_MAGIC_STRING_ERROR_UL; break; } default: { return NULL; } } lit_utf8_size_t size = lit_get_magic_string_size (string_id); JERRY_ASSERT (size <= 14); lit_utf8_byte_t data[16]; memcpy (data, lit_get_magic_string_utf8 (string_id), size); ecma_property_t *property_p; property_p = ecma_find_named_property (ecma_get_object_from_value (exception_obj_value), ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE)); if (property_p == NULL || ECMA_PROPERTY_GET_TYPE (*property_p) != ECMA_PROPERTY_TYPE_NAMEDDATA) { return ecma_new_ecma_string_from_utf8 (data, size); } ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); if (!ecma_is_value_string (prop_value_p->value)) { return ecma_new_ecma_string_from_utf8 (data, size); } data[size] = LIT_CHAR_COLON; data[size + 1] = LIT_CHAR_SP; return ecma_concat_ecma_strings (ecma_new_ecma_string_from_utf8 (data, size + 2), ecma_get_string_from_value (prop_value_p->value)); } /* jerry_debugger_exception_object_to_string */
/** * [[CanPut]] ecma general object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 8.12.4 * * @return true - if [[Put]] with the given property name can be performed; * false - otherwise. */ bool ecma_op_general_object_can_put (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. ecma_property_t *prop_p = ecma_op_object_get_own_property (obj_p, property_name_p); // 2. if (prop_p != NULL) { // a. if (prop_p->type == ECMA_PROPERTY_NAMEDACCESSOR) { ecma_object_t *setter_p = ecma_get_named_accessor_property_setter (prop_p); // i. if (setter_p == NULL) { return false; } // ii. return true; } else { // b. JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA); return ecma_is_property_writable (prop_p); } } // 3. ecma_object_t *proto_p = ecma_get_object_prototype (obj_p); // 4. if (proto_p == NULL) { return ecma_get_object_extensible (obj_p); } // 5. ecma_property_t *inherited_p = ecma_op_object_get_property (proto_p, property_name_p); // 6. if (inherited_p == NULL) { return ecma_get_object_extensible (obj_p); } // 7. if (inherited_p->type == ECMA_PROPERTY_NAMEDACCESSOR) { ecma_object_t *setter_p = ecma_get_named_accessor_property_setter (inherited_p); // a. if (setter_p == NULL) { return false; } // b. return true; } else { // 8. JERRY_ASSERT (inherited_p->type == ECMA_PROPERTY_NAMEDDATA); // a. if (!ecma_get_object_extensible (obj_p)) { return false; } else { // b. return ecma_is_property_writable (inherited_p); } } JERRY_UNREACHABLE (); } /* ecma_op_general_object_can_put */
/** * [[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 */
/** * [[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 */