/** * Handle calling [[Call]] of built-in object * * @return ecma value */ ecma_value_t ecma_builtin_dispatch_call (ecma_object_t *obj_p, /**< built-in object */ ecma_value_t this_arg_value, /**< 'this' argument value */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< arguments list length */ { JERRY_ASSERT (ecma_get_object_is_builtin (obj_p)); ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; if (ecma_builtin_function_is_routine (obj_p)) { ret_value = ecma_builtin_dispatch_routine (ext_obj_p->u.built_in.id, ext_obj_p->u.built_in.routine_id, this_arg_value, arguments_list_p, arguments_list_len); } else { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION); switch ((ecma_builtin_id_t) ext_obj_p->u.built_in.id) { #define BUILTIN(builtin_id, \ object_type, \ object_prototype_builtin_id, \ is_extensible, \ is_static, \ lowercase_name) \ case builtin_id: \ { \ if (object_type == ECMA_OBJECT_TYPE_FUNCTION) \ { \ ret_value = ecma_builtin_ ## lowercase_name ## _dispatch_call (arguments_list_p, \ arguments_list_len); \ } \ break; \ } #include "ecma-builtins.inc.h" case ECMA_BUILTIN_ID__COUNT: { JERRY_UNREACHABLE (); } default: { JERRY_UNREACHABLE (); /* The built-in is not implemented. */ } } } JERRY_ASSERT (!ecma_is_value_empty (ret_value)); return ret_value; } /* ecma_builtin_dispatch_call */
/** * Check whether the value is Object that implements [[Construct]]. * * @return true, if value is constructor object; * false - otherwise. */ bool ecma_is_constructor (ecma_value_t value) /**< ecma value */ { if (!ecma_is_value_object (value)) { return false; } ecma_object_t *obj_p = ecma_get_object_from_value (value); JERRY_ASSERT (obj_p != NULL); JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION) { return (!ecma_get_object_is_builtin (obj_p) || !ecma_builtin_function_is_routine (obj_p)); } return (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION || ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); } /* ecma_is_constructor */
/** * [[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 */
/** * List names of a built-in object's lazy instantiated properties * * See also: * ecma_builtin_try_to_instantiate_property */ void ecma_builtin_list_lazy_property_names (ecma_object_t *object_p, /**< a built-in object */ bool separate_enumerable, /**< true - list enumerable properties into * main collection, and non-enumerable * to collection of 'skipped non-enumerable' * properties, * false - list all properties into main collection. */ ecma_collection_header_t *main_collection_p, /**< 'main' collection */ ecma_collection_header_t *non_enum_collection_p) /**< skipped 'non-enumerable' * collection */ { 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)) { ecma_collection_header_t *for_enumerable_p = main_collection_p; JERRY_UNUSED (for_enumerable_p); ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; /* 'length' property is non-enumerable (ECMA-262 v5, 15) */ ecma_string_t *name_p = ecma_new_ecma_length_string (); ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); ecma_deref_ecma_string (name_p); } else { 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 *curr_property_p = ecma_builtin_property_list_references[builtin_id]; ecma_length_t index = 0; uint32_t instantiated_bitset = ext_obj_p->u.built_in.instantiated_bitset; ecma_collection_header_t *for_non_enumerable_p = (separate_enumerable ? non_enum_collection_p : main_collection_p); while (curr_property_p->magic_string_id != LIT_MAGIC_STRING__COUNT) { JERRY_ASSERT (index < 64); if (index == 32) { ecma_value_t *mask_prop_p = ecma_find_internal_property (object_p, ECMA_INTERNAL_PROPERTY_INSTANTIATED_MASK_32_63); if (mask_prop_p == NULL) { instantiated_bitset = 0; } else { instantiated_bitset = *mask_prop_p; } } uint32_t bit_for_index; if (index >= 32) { bit_for_index = (uint32_t) 1u << (index - 32); } else { bit_for_index = (uint32_t) 1u << index; } bool was_instantiated = false; if (instantiated_bitset & bit_for_index) { was_instantiated = true; } ecma_string_t *name_p = ecma_get_magic_string (curr_property_p->magic_string_id); if (!was_instantiated || ecma_op_object_has_own_property (object_p, name_p)) { ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); } ecma_deref_ecma_string (name_p); curr_property_p++; index++; } } } /* ecma_builtin_list_lazy_property_names */
/** * 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 */