/** * Handle calling [[Construct]] of built-in Number object * * @return ecma value */ ecma_value_t ecma_builtin_number_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< number of arguments */ { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); if (arguments_list_len == 0) { ecma_value_t completion = ecma_op_create_number_object (ecma_make_integer_value (0)); return completion; } else { return ecma_op_create_number_object (arguments_list_p[0]); } } /* ecma_builtin_number_dispatch_construct */
/** * Handle calling [[Call]] of built-in Number object * * @return ecma value */ ecma_value_t ecma_builtin_number_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< number of arguments */ { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); if (arguments_list_len == 0) { ret_value = ecma_make_integer_value (0); } else { ret_value = ecma_op_to_number (arguments_list_p[0]); } return ret_value; } /* ecma_builtin_number_dispatch_call */
/** * ToBoolean operation. Cannot throw an exception. * * See also: * ECMA-262 v5, 9.2 * * @return true if the logical value is true * false otherwise */ bool ecma_op_to_boolean (ecma_value_t value) /**< ecma value */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_simple (value)) { JERRY_ASSERT (ecma_is_value_boolean (value) || ecma_is_value_undefined (value) || ecma_is_value_null (value)); return ecma_is_value_true (value); } if (ecma_is_value_integer_number (value)) { return (value != ecma_make_integer_value (0)); } if (ecma_is_value_float_number (value)) { ecma_number_t num = ecma_get_float_from_value (value); return (!ecma_number_is_nan (num) && !ecma_number_is_zero (num)); } if (ecma_is_value_string (value)) { ecma_string_t *str_p = ecma_get_string_from_value (value); return ecma_string_get_length (str_p) != 0; } JERRY_ASSERT (ecma_is_value_object (value)); return true; } /* ecma_op_to_boolean */
/** * ECMA abstract equality comparison routine. * * See also: ECMA-262 v5, 11.9.3 * * Note: * This function might raise an exception, so the * returned value must be freed with ecma_free_value. * * @return true - if values are equal, * false - otherwise * error - in case of any problems */ ecma_value_t ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ ecma_value_t y) /**< second operand */ { if (x == y) { return ECMA_VALUE_TRUE; } if (ecma_are_values_integer_numbers (x, y)) { /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } if (ecma_is_value_number (x)) { if (ecma_is_value_number (y)) { /* 1.c */ ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); bool is_x_equal_to_y = (x_num == y_num); #ifndef JERRY_NDEBUG bool is_x_equal_to_y_check; if (ecma_number_is_nan (x_num) || ecma_number_is_nan (y_num)) { is_x_equal_to_y_check = false; } else if (x_num == y_num || (ecma_number_is_zero (x_num) && ecma_number_is_zero (y_num))) { is_x_equal_to_y_check = true; } else { is_x_equal_to_y_check = false; } JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); #endif /* !JERRY_NDEBUG */ return ecma_make_boolean_value (is_x_equal_to_y); } /* Swap values. */ ecma_value_t tmp = x; x = y; y = tmp; } if (ecma_is_value_string (x)) { if (ecma_is_value_string (y)) { /* 1., d. */ ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); bool is_equal = ecma_compare_ecma_strings (x_str_p, y_str_p); return ecma_make_boolean_value (is_equal); } if (ecma_is_value_number (y)) { /* 4. */ ecma_value_t x_num_value = ecma_op_to_number (x); if (ECMA_IS_VALUE_ERROR (x_num_value)) { return x_num_value; } ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_num_value, y); ecma_free_value (x_num_value); return compare_result; } /* Swap values. */ ecma_value_t tmp = x; x = y; y = tmp; } #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) if (ecma_is_value_symbol (x)) { return ECMA_VALUE_FALSE; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ if (ecma_is_value_boolean (y)) { if (ecma_is_value_boolean (x)) { /* 1., e. */ /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } /* 7. */ return ecma_op_abstract_equality_compare (x, ecma_make_integer_value (ecma_is_value_true (y) ? 1 : 0)); } if (ecma_is_value_object (x)) { if (ecma_is_value_string (y) #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) || ecma_is_value_symbol (y) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ || ecma_is_value_number (y)) { /* 9. */ ecma_value_t x_prim_value = ecma_op_to_primitive (x, ECMA_PREFERRED_TYPE_NO); if (ECMA_IS_VALUE_ERROR (x_prim_value)) { return x_prim_value; } ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_prim_value, y); ecma_free_value (x_prim_value); return compare_result; } /* 1., f. */ /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } if (ecma_is_value_boolean (x)) { /* 6. */ return ecma_op_abstract_equality_compare (ecma_make_integer_value (ecma_is_value_true (x) ? 1 : 0), y); } if (ecma_is_value_undefined (x) || ecma_is_value_null (x)) { /* 1. a., b. */ /* 2., 3. */ bool is_equal = ecma_is_value_undefined (y) || ecma_is_value_null (y); return ecma_make_boolean_value (is_equal); } return ECMA_VALUE_FALSE; } /* ecma_op_abstract_equality_compare */
/** * ECMA strict equality comparison routine. * * See also: ECMA-262 v5, 11.9.6 * * @return true - if values are strict equal, * false - otherwise */ bool ecma_op_strict_equality_compare (ecma_value_t x, /**< first operand */ ecma_value_t y) /**< second operand */ { if (ecma_is_value_direct (x) || ecma_is_value_direct (y) #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) || ecma_is_value_symbol (x) || ecma_is_value_symbol (y) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ || ecma_is_value_object (x) || ecma_is_value_object (y)) { JERRY_ASSERT (!ecma_is_value_direct (x) || ecma_is_value_undefined (x) || ecma_is_value_null (x) || ecma_is_value_boolean (x) || ecma_is_value_integer_number (x)); JERRY_ASSERT (!ecma_is_value_direct (y) || ecma_is_value_undefined (y) || ecma_is_value_null (y) || ecma_is_value_boolean (y) || ecma_is_value_integer_number (y)); if ((x != ecma_make_integer_value (0) || !ecma_is_value_float_number (y)) && (y != ecma_make_integer_value (0) || !ecma_is_value_float_number (x))) { return (x == y); } /* The +0 === -0 case handled below. */ } JERRY_ASSERT (ecma_is_value_number (x) || ecma_is_value_string (x)); JERRY_ASSERT (ecma_is_value_number (y) || ecma_is_value_string (y)); if (ecma_is_value_string (x)) { if (!ecma_is_value_string (y)) { return false; } ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); return ecma_compare_ecma_strings (x_str_p, y_str_p); } if (!ecma_is_value_number (y)) { return false; } ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); bool is_x_equal_to_y = (x_num == y_num); #ifndef JERRY_NDEBUG bool is_x_equal_to_y_check; if (ecma_number_is_nan (x_num) || ecma_number_is_nan (y_num)) { is_x_equal_to_y_check = false; } else if (x_num == y_num || (ecma_number_is_zero (x_num) && ecma_number_is_zero (y_num))) { is_x_equal_to_y_check = true; } else { is_x_equal_to_y_check = false; } JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); #endif /* !JERRY_NDEBUG */ return is_x_equal_to_y; } /* ecma_op_strict_equality_compare */
/** * ToNumber operation. * * See also: * ECMA-262 v5, 9.3 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_to_number (ecma_value_t value) /**< ecma value */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_integer_number (value)) { return value; } else if (ecma_is_value_float_number (value)) { return ecma_copy_value (value); } else if (ecma_is_value_string (value)) { ecma_string_t *str_p = ecma_get_string_from_value (value); return ecma_make_number_value (ecma_string_to_number (str_p)); } else if (ecma_is_value_object (value)) { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (primitive_value, ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_NUMBER), ret_value); ret_value = ecma_op_to_number (primitive_value); ECMA_FINALIZE (primitive_value); return ret_value; } else { int16_t num = 0; if (ecma_is_value_undefined (value)) { return ecma_make_nan_value (); } else if (ecma_is_value_null (value)) { num = 0; } else { JERRY_ASSERT (ecma_is_value_boolean (value)); if (ecma_is_value_true (value)) { num = 1; } else { num = 0; } } return ecma_make_integer_value (num); } } /* ecma_op_to_number */
/** * 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 */
/** * The Function.prototype object's 'bind' routine * * See also: * ECMA-262 v5, 15.3.4.5 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this argument */ const ecma_value_t *arguments_list_p, /**< list of arguments */ ecma_length_t arguments_number) /**< number of arguments */ { ecma_value_t ret_value = ECMA_VALUE_EMPTY; /* 2. */ if (!ecma_op_is_callable (this_arg)) { ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a function.")); } else { /* 4. 11. 18. */ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); ecma_length_t args_length = arguments_number; ecma_object_t *function_p; ecma_extended_object_t *ext_function_p; if (arguments_number == 0 || (arguments_number == 1 && !ecma_is_value_integer_number (arguments_list_p[0]))) { args_length = 1; function_p = ecma_create_object (prototype_obj_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_BOUND_FUNCTION); /* 8. */ ext_function_p = (ecma_extended_object_t *) function_p; ecma_object_t *this_arg_obj_p = ecma_get_object_from_value (this_arg); ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function, this_arg_obj_p); ext_function_p->u.bound_function.args_len_or_this = ECMA_VALUE_UNDEFINED; if (arguments_number != 0) { ext_function_p->u.bound_function.args_len_or_this = ecma_copy_value_if_not_object (arguments_list_p[0]); } } else { JERRY_ASSERT (arguments_number > 0); size_t obj_size = sizeof (ecma_extended_object_t) + (args_length * sizeof (ecma_value_t)); function_p = ecma_create_object (prototype_obj_p, obj_size, ECMA_OBJECT_TYPE_BOUND_FUNCTION); /* 8. */ ext_function_p = (ecma_extended_object_t *) function_p; ecma_object_t *this_arg_obj_p = ecma_get_object_from_value (this_arg); ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function, this_arg_obj_p); /* NOTE: This solution provides temporary false data about the object's size but prevents GC from freeing it until it's not fully initialized. */ ext_function_p->u.bound_function.args_len_or_this = ECMA_VALUE_UNDEFINED; ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1); for (ecma_length_t i = 0; i < arguments_number; i++) { *args_p++ = ecma_copy_value_if_not_object (arguments_list_p[i]); } ecma_value_t args_len_or_this = ecma_make_integer_value ((ecma_integer_value_t) args_length); ext_function_p->u.bound_function.args_len_or_this = args_len_or_this; } ecma_deref_object (prototype_obj_p); /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type. * * See also: ecma_object_get_class_name */ /* 22. */ ret_value = ecma_make_object_value (function_p); } return ret_value; } /* ecma_builtin_function_prototype_object_bind */