/** * Reject the promise if the value is error. * * See also: * ES2015 25.4.1.1.1 * * @return ecma value of the new promise. * Returned value must be freed with ecma_free_value. */ inline static ecma_value_t ecma_builtin_promise_reject_abrupt (ecma_value_t capability) /**< reject description */ { ecma_value_t reason = JERRY_CONTEXT (error_value); ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_reject); ecma_deref_ecma_string (str_reject); ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (reject), ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), &reason, 1); ecma_free_value (reject); if (ECMA_IS_VALUE_ERROR (call_ret)) { return call_ret; } ecma_free_value (call_ret); ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), str_promise); ecma_deref_ecma_string (str_promise); return promise_new; } /* ecma_builtin_promise_reject_abrupt */
/** * Free the heap and the member of the PromiseReactionJob. */ static void ecma_free_promise_reaction_job (ecma_job_promise_reaction_t *job_p) /**< points to the PromiseReactionJob */ { JERRY_ASSERT (job_p != NULL); ecma_free_value (job_p->reaction); ecma_free_value (job_p->argument); jmem_heap_free_block (job_p, sizeof (ecma_job_promise_reaction_t)); } /* ecma_free_promise_reaction_job */
/** * Free the heap and the member of the PromiseResolveThenableJob. */ static void ecma_free_promise_resolve_thenable_job (ecma_job_promise_resolve_thenable_t *job_p) /**< points to the * PromiseResolveThenableJob */ { JERRY_ASSERT (job_p != NULL); ecma_free_value (job_p->promise); ecma_free_value (job_p->thenable); ecma_free_value (job_p->then); jmem_heap_free_block (job_p, sizeof (ecma_job_promise_resolve_thenable_t)); } /* ecma_free_promise_resolve_thenable_job */
/** * 'in' opcode handler. * * See also: ECMA-262 v5, 11.8.7 * * @return ecma value * returned value must be freed with ecma_free_value. */ ecma_value_t opfunc_in (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { if (!ecma_is_value_object (right_value)) { return ecma_raise_type_error (ECMA_ERR_MSG ("Expected an object in 'in' check.")); } bool to_string = !ecma_is_value_string (left_value); if (to_string) { left_value = ecma_op_to_string (left_value); if (ECMA_IS_VALUE_ERROR (left_value)) { return left_value; } } ecma_string_t *left_value_prop_name_p = ecma_get_string_from_value (left_value); ecma_object_t *right_value_obj_p = ecma_get_object_from_value (right_value); ecma_value_t result = ecma_make_boolean_value (ecma_op_object_has_property (right_value_obj_p, left_value_prop_name_p)); if (to_string) { ecma_free_value (left_value); } return result; } /* opfunc_in */
/** * Free specified ECMA-reference. * * Warning: * freeing invalidates all copies of the reference. */ void ecma_free_reference (ecma_reference_t ref) /**< reference */ { ecma_free_value (ref.base); ecma_deref_ecma_string (ECMA_GET_NON_NULL_POINTER (ecma_string_t, ref.referenced_name_cp)); } /* ecma_free_reference */
/** * [[GetOwnProperty]] ecma Arguments object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 10.6 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_property_t * ecma_op_arguments_object_get_own_property (ecma_object_t *obj_p, /**< the object */ ecma_string_t *property_name_p) /**< property name */ { // 1. ecma_property_t *desc_p = ecma_op_general_object_get_own_property (obj_p, property_name_p); // 2. if (desc_p == NULL) { return desc_p; } // 3. ecma_property_t *map_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP); ecma_object_t *map_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ECMA_PROPERTY_VALUE_PTR (map_prop_p)->value); // 4. ecma_property_t *mapped_prop_p = ecma_op_object_get_own_property (map_p, property_name_p); // 5. if (mapped_prop_p != NULL) { // a. ecma_value_t completion = ecma_arguments_get_mapped_arg_value (map_p, mapped_prop_p); ecma_named_data_property_assign_value (obj_p, desc_p, completion); ecma_free_value (completion); } // 6. return desc_p; } /* ecma_op_arguments_object_get_own_property */
/** * Free the ecma value if not an object */ void ecma_free_value_if_not_object (ecma_value_t value) /**< value description */ { if (ecma_get_value_type_field (value) != ECMA_TYPE_OBJECT) { ecma_free_value (value); } } /* ecma_free_value_if_not_object */
/** * Remove last element of the collection * * Warning: * the function invalidates all iterators that are configured to access the passed collection */ void ecma_remove_last_value_from_values_collection (ecma_collection_header_t *header_p, /**< collection's header */ bool do_deref_if_object) /**< if the value to remove * is object value, decrement * reference counter of the object */ { JERRY_ASSERT (header_p != NULL && header_p->unit_number > 0); const size_t values_in_chunk = sizeof (ecma_collection_chunk_t::data) / sizeof (ecma_value_t); size_t values_number = header_p->unit_number; size_t pos_of_value_to_remove_in_chunk = (values_number - 1u) % values_in_chunk; ecma_collection_chunk_t *last_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, header_p->last_chunk_cp); ecma_value_t *values_p = (ecma_value_t *) last_chunk_p->data; JERRY_ASSERT ((uint8_t *) (values_p + pos_of_value_to_remove_in_chunk + 1) <= (uint8_t *) (last_chunk_p + 1)); ecma_value_t value_to_remove = values_p[pos_of_value_to_remove_in_chunk]; ecma_free_value (value_to_remove, do_deref_if_object); header_p->unit_number--; if (pos_of_value_to_remove_in_chunk == 0) { ecma_collection_chunk_t *chunk_to_remove_p = last_chunk_p; /* free last chunk */ if (header_p->first_chunk_cp == header_p->last_chunk_cp) { header_p->first_chunk_cp = ECMA_NULL_POINTER; header_p->last_chunk_cp = ECMA_NULL_POINTER; } else { ecma_collection_chunk_t *chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, header_p->first_chunk_cp); while (chunk_iter_p->next_chunk_cp != header_p->last_chunk_cp) { chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, chunk_iter_p->next_chunk_cp); } ecma_collection_chunk_t *new_last_chunk_p = chunk_iter_p; JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, new_last_chunk_p->next_chunk_cp) == chunk_to_remove_p); ECMA_SET_NON_NULL_POINTER (header_p->last_chunk_cp, new_last_chunk_p); new_last_chunk_p->next_chunk_cp = ECMA_NULL_POINTER; } ecma_dealloc_collection_chunk (chunk_to_remove_p); } } /* ecma_remove_last_value_from_values_collection */
/** * Remove last element of the collection * * Warning: * the function invalidates all iterators that are configured to access the passed collection */ void ecma_remove_last_value_from_values_collection (ecma_collection_header_t *header_p) /**< collection's header */ { JERRY_ASSERT (header_p != NULL && header_p->unit_number > 0); const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); size_t values_number = header_p->unit_number; size_t pos_of_value_to_remove_in_chunk = (values_number - 1u) % values_in_chunk; ecma_collection_chunk_t *last_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, header_p->last_chunk_cp); ecma_value_t *values_p = (ecma_value_t *) last_chunk_p->data; JERRY_ASSERT ((uint8_t *) (values_p + pos_of_value_to_remove_in_chunk + 1) <= (uint8_t *) (last_chunk_p + 1)); ecma_value_t value_to_remove = values_p[pos_of_value_to_remove_in_chunk]; ecma_free_value (value_to_remove); header_p->unit_number--; if (pos_of_value_to_remove_in_chunk == 0) { ecma_collection_chunk_t *chunk_to_remove_p = last_chunk_p; /* free last chunk */ if (header_p->first_chunk_cp == header_p->last_chunk_cp) { header_p->first_chunk_cp = ECMA_NULL_POINTER; header_p->last_chunk_cp = ECMA_NULL_POINTER; } else { ecma_collection_chunk_t *chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, header_p->first_chunk_cp); while (chunk_iter_p->next_chunk_cp != header_p->last_chunk_cp) { chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, chunk_iter_p->next_chunk_cp); } ecma_collection_chunk_t *new_last_chunk_p = chunk_iter_p; JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, new_last_chunk_p->next_chunk_cp) == chunk_to_remove_p); ECMA_SET_NON_NULL_POINTER (header_p->last_chunk_cp, new_last_chunk_p); new_last_chunk_p->next_chunk_cp = ECMA_NULL_POINTER; } ecma_dealloc_collection_chunk (chunk_to_remove_p); } } /* ecma_remove_last_value_from_values_collection */
/** * Run specified eval-mode bytecode * * @return completion value */ ecma_completion_value_t vm_run_eval (const bytecode_data_header_t *bytecode_data_p, /**< byte-code data header */ bool is_direct) /**< is eval called in direct mode? */ { vm_instr_counter_t first_instr_index = 0u; opcode_scope_code_flags_t scope_flags = vm_get_scope_flags (bytecode_data_p, first_instr_index++); bool is_strict = ((scope_flags & OPCODE_SCOPE_CODE_FLAGS_STRICT) != 0); ecma_value_t this_binding; ecma_object_t *lex_env_p; /* ECMA-262 v5, 10.4.2 */ if (is_direct) { this_binding = vm_get_this_binding (); lex_env_p = vm_get_lex_env (); } else { this_binding = ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL)); lex_env_p = ecma_get_global_environment (); } if (is_strict) { ecma_object_t *strict_lex_env_p = ecma_create_decl_lex_env (lex_env_p); ecma_deref_object (lex_env_p); lex_env_p = strict_lex_env_p; } ecma_completion_value_t completion = vm_run_from_pos (bytecode_data_p, first_instr_index, this_binding, lex_env_p, is_strict, true, NULL); if (ecma_is_completion_value_return (completion)) { completion = ecma_make_normal_completion_value (ecma_get_completion_value_value (completion)); } else { JERRY_ASSERT (ecma_is_completion_value_throw (completion)); } ecma_deref_object (lex_env_p); ecma_free_value (this_binding, true); return completion; } /* vm_run_eval */
/** * Process the PromiseResolveThenableJob. * * See also: ES2015 25.4.2.2 * * @return ecma value * Returned value must be freed with ecma_free_value */ static ecma_value_t ecma_process_promise_resolve_thenable_job (void *obj_p) /**< the job to be operated */ { ecma_job_promise_resolve_thenable_t *job_p = (ecma_job_promise_resolve_thenable_t *) obj_p; ecma_object_t *promise_p = ecma_get_object_from_value (job_p->promise); ecma_string_t str_resolve, str_reject; ecma_init_ecma_magic_string (&str_resolve, LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION); ecma_init_ecma_magic_string (&str_reject, LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION); ecma_value_t resolve = ecma_op_object_get (promise_p, &str_resolve); ecma_value_t reject = ecma_op_object_get (promise_p, &str_reject); ecma_value_t argv[] = { resolve, reject }; ecma_value_t ret; ecma_value_t then_call_result = ecma_op_function_call (ecma_get_object_from_value (job_p->then), job_p->thenable, argv, 2); ret = then_call_result; if (ECMA_IS_VALUE_ERROR (then_call_result)) { ret = ecma_op_function_call (ecma_get_object_from_value (reject), ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), &then_call_result, 1); ecma_free_value (then_call_result); } ecma_free_value (resolve); ecma_free_value (reject); ecma_free_promise_resolve_thenable_job (job_p); return ret; } /* ecma_process_promise_resolve_thenable_job */
/** * ArrayBuffer object creation operation. * * See also: ES2015 24.1.1.1 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_create_arraybuffer_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_number_t length_num = 0; if (arguments_list_len > 0) { if (ecma_is_value_number (arguments_list_p[0])) { length_num = ecma_get_number_from_value (arguments_list_p[0]); } else { ecma_value_t to_number_value = ecma_op_to_number (arguments_list_p[0]); if (ECMA_IS_VALUE_ERROR (to_number_value)) { return to_number_value; } length_num = ecma_get_number_from_value (to_number_value); ecma_free_value (to_number_value); } if (ecma_number_is_nan (length_num)) { length_num = 0; } const uint32_t maximum_size_in_byte = UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1; if (length_num <= -1.0 || length_num > (double) maximum_size_in_byte + 0.5) { return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid ArrayBuffer length.")); } } uint32_t length_uint32 = ecma_number_to_uint32 (length_num); return ecma_make_object_value (ecma_arraybuffer_new_object (length_uint32)); } /* ecma_op_create_arraybuffer_object */
/** * Free the collection of ecma values. */ void ecma_free_values_collection (ecma_collection_header_t *header_p, /**< collection's header */ bool do_deref_if_object) /**< if the value is object value, decrement reference counter of the object */ { JERRY_ASSERT (header_p != NULL); const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); ecma_collection_chunk_t *chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, header_p->first_chunk_cp); ecma_length_t value_index = 0; while (chunk_p != NULL) { JERRY_ASSERT (value_index < header_p->unit_number); ecma_value_t *cur_value_buf_iter_p = (ecma_value_t *) chunk_p->data; ecma_value_t *cur_value_buf_end_p = cur_value_buf_iter_p + values_in_chunk; while (cur_value_buf_iter_p != cur_value_buf_end_p && value_index < header_p->unit_number) { JERRY_ASSERT (cur_value_buf_iter_p < cur_value_buf_end_p); if (do_deref_if_object) { ecma_free_value (*cur_value_buf_iter_p); } else { ecma_free_value_if_not_object (*cur_value_buf_iter_p); } cur_value_buf_iter_p++; value_index++; } ecma_collection_chunk_t *next_chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, chunk_p->next_chunk_cp); ecma_dealloc_collection_chunk (chunk_p); chunk_p = next_chunk_p; } ecma_dealloc_collection_header (header_p); } /* ecma_free_values_collection */
/** * Process enqueued Promise jobs until the first thrown error or until the * jobqueue becomes empty. * * @return result of the last processed job - if the jobqueue was non-empty, * undefined - otherwise. */ ecma_value_t ecma_process_all_enqueued_jobs (void) { ecma_value_t ret = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); while (JERRY_CONTEXT (job_queue_head_p) != NULL && !ECMA_IS_VALUE_ERROR (ret)) { ecma_job_queueitem_t *item_p = JERRY_CONTEXT (job_queue_head_p); JERRY_CONTEXT (job_queue_head_p) = JERRY_CONTEXT (job_queue_head_p)->next_p; void *job_p = item_p->job_p; ecma_job_handler_t handler = item_p->handler; jmem_heap_free_block (item_p, sizeof (ecma_job_queueitem_t)); ecma_free_value (ret); ret = handler (job_p); } return ret; } /* ecma_process_all_enqueued_jobs */
/** * Free values contained in the property descriptor * and make it empty property descriptor */ void ecma_free_property_descriptor (ecma_property_descriptor_t *prop_desc_p) /**< property descriptor */ { if (prop_desc_p->is_value_defined) { ecma_free_value (prop_desc_p->value); } if (prop_desc_p->is_get_defined && prop_desc_p->get_p != NULL) { ecma_deref_object (prop_desc_p->get_p); } if (prop_desc_p->is_set_defined && prop_desc_p->set_p != NULL) { ecma_deref_object (prop_desc_p->set_p); } *prop_desc_p = ecma_make_empty_property_descriptor (); } /* ecma_free_property_descriptor */
/** * Get value of function's argument mapped to index of Arguments object. * * Note: * The procedure emulates execution of function described by MakeArgGetter * * @return ecma value * Returned value must be freed with ecma_free_value */ void ecma_arguments_update_mapped_arg_value (ecma_object_t *object_p, /**< the object */ ecma_string_t *property_name_p, /**< property name */ ecma_property_t *property_p) /**< property value */ { ecma_value_t *map_prop_p = ecma_get_internal_property (object_p, ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP); ecma_object_t *map_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, *map_prop_p); ecma_value_t arg_name = ecma_op_object_find (map_p, property_name_p); if (!ecma_is_value_found (arg_name)) { return; } ecma_value_t *scope_prop_p = ecma_get_internal_property (map_p, ECMA_INTERNAL_PROPERTY_SCOPE); ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, *scope_prop_p); JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); ecma_string_t *arg_name_p = ecma_get_string_from_value (arg_name); ecma_value_t value = ecma_op_get_binding_value (lex_env_p, arg_name_p, true); ecma_deref_ecma_string (arg_name_p); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (value)); ecma_named_data_property_assign_value (object_p, property_p, value); ecma_free_value (value); /* These properties cannot be cached. This is a temporary * workaround until the property management is fully rewritten. */ if (ecma_is_property_lcached (property_p)) { ecma_lcache_invalidate (object_p, property_name_p, property_p); } } /* ecma_arguments_update_mapped_arg_value */
/** * 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 */
/** * Dispatch set date functions * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_date_prototype_dispatch_set (uint16_t builtin_routine_id, /**< built-in wide routine * identifier */ ecma_extended_object_t *ext_object_p, /**< date extended object */ ecma_number_t date_num, /**< date converted to number */ const ecma_value_t arguments_list[], /**< list of arguments * passed to routine */ ecma_length_t arguments_number) /**< length of arguments' list */ { ecma_number_t converted_number[4]; ecma_length_t conversions = 0; /* If the first argument is not specified, it is always converted to NaN. */ converted_number[0] = ecma_number_make_nan (); switch (builtin_routine_id) { #ifndef CONFIG_DISABLE_ANNEXB_BUILTIN case ECMA_DATE_PROTOTYPE_SET_YEAR: #endif /* !CONFIG_DISABLE_ANNEXB_BUILTIN */ case ECMA_DATE_PROTOTYPE_SET_DATE: case ECMA_DATE_PROTOTYPE_SET_UTC_DATE: case ECMA_DATE_PROTOTYPE_SET_UTC_MILLISECONDS: case ECMA_DATE_PROTOTYPE_SET_MILLISECONDS: { conversions = 1; break; } case ECMA_DATE_PROTOTYPE_SET_MONTH: case ECMA_DATE_PROTOTYPE_SET_UTC_MONTH: case ECMA_DATE_PROTOTYPE_SET_UTC_SECONDS: case ECMA_DATE_PROTOTYPE_SET_SECONDS: { conversions = 2; break; } case ECMA_DATE_PROTOTYPE_SET_FULL_YEAR: case ECMA_DATE_PROTOTYPE_SET_UTC_FULL_YEAR: case ECMA_DATE_PROTOTYPE_SET_MINUTES: case ECMA_DATE_PROTOTYPE_SET_UTC_MINUTES: { conversions = 3; break; } default: { JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_HOURS || builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_UTC_HOURS); conversions = 4; break; } } if (conversions > arguments_number) { conversions = arguments_number; } for (ecma_length_t i = 0; i < conversions; i++) { ecma_value_t value = ecma_op_to_number (arguments_list[i]); if (ECMA_IS_VALUE_ERROR (value)) { return value; } converted_number[i] = ecma_get_number_from_value (value); ecma_free_value (value); } ecma_number_t day_part; ecma_number_t time_part; if (builtin_routine_id <= ECMA_DATE_PROTOTYPE_SET_UTC_DATE) { if (ecma_number_is_nan (date_num)) { if (ECMA_DATE_PROTOTYPE_IS_SET_YEAR_ROUTINE (builtin_routine_id)) { date_num = ECMA_NUMBER_ZERO; } else { return ecma_make_number_value (date_num); } } time_part = ecma_date_time_within_day (date_num); ecma_number_t year = ecma_date_year_from_time (date_num); ecma_number_t month = ecma_date_month_from_time (date_num); ecma_number_t day = ecma_date_date_from_time (date_num); switch (builtin_routine_id) { case ECMA_DATE_PROTOTYPE_SET_FULL_YEAR: case ECMA_DATE_PROTOTYPE_SET_UTC_FULL_YEAR: { year = converted_number[0]; if (conversions >= 2) { month = converted_number[1]; } if (conversions >= 3) { day = converted_number[2]; } break; } #ifndef CONFIG_DISABLE_ANNEXB_BUILTIN case ECMA_DATE_PROTOTYPE_SET_YEAR: { year = converted_number[0]; if (year >= 0 && year <= 99) { year += 1900; } break; } #endif /* !CONFIG_DISABLE_ANNEXB_BUILTIN */ case ECMA_DATE_PROTOTYPE_SET_MONTH: case ECMA_DATE_PROTOTYPE_SET_UTC_MONTH: { month = converted_number[0]; if (conversions >= 2) { day = converted_number[1]; } break; } default: { JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_DATE || builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_UTC_DATE); day = converted_number[0]; break; } } day_part = ecma_date_make_day (year, month, day); #ifndef CONFIG_DISABLE_ANNEXB_BUILTIN if (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_YEAR) { builtin_routine_id = ECMA_DATE_PROTOTYPE_SET_UTC_YEAR; if (ecma_number_is_nan (converted_number[0])) { day_part = 0; time_part = converted_number[0]; } } #endif /* !CONFIG_DISABLE_ANNEXB_BUILTIN */ } else { if (ecma_number_is_nan (date_num)) { return ecma_make_number_value (date_num); } day_part = ecma_date_day (date_num); ecma_number_t hour = ecma_date_hour_from_time (date_num); ecma_number_t min = ecma_date_min_from_time (date_num); ecma_number_t sec = ecma_date_sec_from_time (date_num); ecma_number_t ms = ecma_date_ms_from_time (date_num); switch (builtin_routine_id) { case ECMA_DATE_PROTOTYPE_SET_HOURS: case ECMA_DATE_PROTOTYPE_SET_UTC_HOURS: { hour = converted_number[0]; if (conversions >= 2) { min = converted_number[1]; } if (conversions >= 3) { sec = converted_number[2]; } if (conversions >= 4) { ms = converted_number[3]; } break; } case ECMA_DATE_PROTOTYPE_SET_MINUTES: case ECMA_DATE_PROTOTYPE_SET_UTC_MINUTES: { min = converted_number[0]; if (conversions >= 2) { sec = converted_number[1]; } if (conversions >= 3) { ms = converted_number[2]; } break; } case ECMA_DATE_PROTOTYPE_SET_UTC_SECONDS: case ECMA_DATE_PROTOTYPE_SET_SECONDS: { sec = converted_number[0]; if (conversions >= 2) { ms = converted_number[1]; } break; } default: { JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_UTC_MILLISECONDS || builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_MILLISECONDS); ms = converted_number[0]; break; } } time_part = ecma_date_make_time (hour, min, sec, ms); } bool is_utc = BUILTIN_DATE_FUNCTION_IS_UTC (builtin_routine_id); ecma_number_t full_date = ecma_date_make_date (day_part, time_part); if (!is_utc) { full_date = ecma_date_utc (full_date); } full_date = ecma_date_time_clip (full_date); *ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, ext_object_p->u.class_prop.u.value) = full_date; return ecma_make_number_value (full_date); } /* ecma_builtin_date_prototype_dispatch_set */
/** * Abort (finalize) the current stack context, and remove it. * * @return new stack top */ ecma_value_t * vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ ecma_value_t *vm_stack_top_p) /**< current stack top */ { switch (VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1])) { case VM_CONTEXT_FINALLY_THROW: case VM_CONTEXT_FINALLY_RETURN: { ecma_free_value (vm_stack_top_p[-2]); VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION); vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; break; } case VM_CONTEXT_FINALLY_JUMP: case VM_CONTEXT_TRY: { VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION); vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; break; } case VM_CONTEXT_CATCH: case VM_CONTEXT_WITH: { ecma_deref_object (frame_ctx_p->lex_env_p); frame_ctx_p->lex_env_p = ecma_get_object_from_value (vm_stack_top_p[-2]); JERRY_ASSERT (PARSER_TRY_CONTEXT_STACK_ALLOCATION == PARSER_WITH_CONTEXT_STACK_ALLOCATION); VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION); vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; break; } case VM_CONTEXT_FOR_IN: { jmem_cpointer_t current = (jmem_cpointer_t) vm_stack_top_p[-2]; while (current != JMEM_CP_NULL) { ecma_collection_chunk_t *chunk_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_collection_chunk_t, current); lit_utf8_byte_t *data_ptr = chunk_p->data; ecma_free_value (*(ecma_value_t *) data_ptr); current = chunk_p->next_chunk_cp; ecma_dealloc_collection_chunk (chunk_p); } ecma_free_value (vm_stack_top_p[-3]); VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); vm_stack_top_p -= PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; break; } default: { JERRY_UNREACHABLE (); break; } } return vm_stack_top_p; } /* vm_stack_context_abort */
/** * [[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_call (ecma_object_t *func_obj_p, /**< Function object */ ecma_value_t this_arg_value, /**< 'this' argument's value */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< length of arguments list */ { JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p)); JERRY_ASSERT (ecma_op_is_callable (ecma_make_object_value (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 (unlikely (ecma_get_object_is_builtin (func_obj_p))) { ret_value = ecma_builtin_dispatch_call (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); } else { /* Entering Function Code (ECMA-262 v5, 10.4.3) */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_obj_p; ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ext_func_p->u.function.scope_cp); // 8. ecma_value_t this_binding; bool is_strict; bool is_no_lex_env; const ecma_compiled_code_t *bytecode_data_p; bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, ext_func_p->u.function.bytecode_cp); is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) ? true : false; is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false; // 1. if (is_strict) { this_binding = ecma_copy_value (this_arg_value); } else if (ecma_is_value_undefined (this_arg_value) || ecma_is_value_null (this_arg_value)) { // 2. this_binding = ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL)); } else { // 3., 4. this_binding = ecma_op_to_object (this_arg_value); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (this_binding)); } // 5. ecma_object_t *local_env_p; if (is_no_lex_env) { local_env_p = scope_p; } else { local_env_p = ecma_create_decl_lex_env (scope_p); if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED) { ecma_op_create_arguments_object (func_obj_p, local_env_p, arguments_list_p, arguments_list_len, bytecode_data_p); } } ret_value = vm_run (bytecode_data_p, this_binding, local_env_p, false, arguments_list_p, arguments_list_len); if (!is_no_lex_env) { ecma_deref_object (local_env_p); } ecma_free_value (this_binding); } } else if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
/** * 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 abstract relational comparison routine. * * See also: ECMA-262 v5, 11.8.5 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_abstract_relational_compare (ecma_value_t x, /**< first operand */ ecma_value_t y, /**< second operand */ bool left_first) /**< 'LeftFirst' flag */ { ecma_value_t ret_value = ECMA_VALUE_EMPTY; /* 1., 2. */ ecma_value_t prim_first_converted_value = ecma_op_to_primitive (x, ECMA_PREFERRED_TYPE_NUMBER); if (ECMA_IS_VALUE_ERROR (prim_first_converted_value)) { return prim_first_converted_value; } ecma_value_t prim_second_converted_value = ecma_op_to_primitive (y, ECMA_PREFERRED_TYPE_NUMBER); if (ECMA_IS_VALUE_ERROR (prim_second_converted_value)) { ecma_free_value (prim_first_converted_value); return prim_second_converted_value; } const ecma_value_t px = left_first ? prim_first_converted_value : prim_second_converted_value; const ecma_value_t py = left_first ? prim_second_converted_value : prim_first_converted_value; const bool is_px_string = ecma_is_value_string (px); const bool is_py_string = ecma_is_value_string (py); if (!(is_px_string && is_py_string)) { /* 3. */ /* a. */ ECMA_OP_TO_NUMBER_TRY_CATCH (nx, px, ret_value); ECMA_OP_TO_NUMBER_TRY_CATCH (ny, py, ret_value); /* b. */ if (ecma_number_is_nan (nx) || ecma_number_is_nan (ny)) { /* c., d. */ ret_value = ECMA_VALUE_UNDEFINED; } else { bool is_x_less_than_y = (nx < ny); #ifndef JERRY_NDEBUG bool is_x_less_than_y_check; if (nx == ny || (ecma_number_is_zero (nx) && ecma_number_is_zero (ny))) { /* e., f., g. */ is_x_less_than_y_check = false; } else if (ecma_number_is_infinity (nx) && !ecma_number_is_negative (nx)) { /* h. */ is_x_less_than_y_check = false; } else if (ecma_number_is_infinity (ny) && !ecma_number_is_negative (ny)) { /* i. */ is_x_less_than_y_check = true; } else if (ecma_number_is_infinity (ny) && ecma_number_is_negative (ny)) { /* j. */ is_x_less_than_y_check = false; } else if (ecma_number_is_infinity (nx) && ecma_number_is_negative (nx)) { /* k. */ is_x_less_than_y_check = true; } else { /* l. */ JERRY_ASSERT (!ecma_number_is_nan (nx) && !ecma_number_is_infinity (nx)); JERRY_ASSERT (!ecma_number_is_nan (ny) && !ecma_number_is_infinity (ny)); JERRY_ASSERT (!(ecma_number_is_zero (nx) && ecma_number_is_zero (ny))); if (nx < ny) { is_x_less_than_y_check = true; } else { is_x_less_than_y_check = false; } } JERRY_ASSERT (is_x_less_than_y_check == is_x_less_than_y); #endif /* !JERRY_NDEBUG */ ret_value = ecma_make_boolean_value (is_x_less_than_y); } ECMA_OP_TO_NUMBER_FINALIZE (ny); ECMA_OP_TO_NUMBER_FINALIZE (nx); } else { /* 4. */ JERRY_ASSERT (is_px_string && is_py_string); ecma_string_t *str_x_p = ecma_get_string_from_value (px); ecma_string_t *str_y_p = ecma_get_string_from_value (py); bool is_px_less = ecma_compare_ecma_strings_relational (str_x_p, str_y_p); ret_value = ecma_make_boolean_value (is_px_less); } ecma_free_value (prim_second_converted_value); ecma_free_value (prim_first_converted_value); return ret_value; } /* ecma_op_abstract_relational_compare */
/** * [[DefineOwnProperty]] ecma array object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 15.4.5.1 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_array_object_define_own_property (ecma_object_t *obj_p, /**< the array 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 (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY); // 1. 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); JERRY_ASSERT (len_prop_p != NULL && len_prop_p->type == ECMA_PROPERTY_NAMEDDATA); // 2. ecma_value_t old_len_value = ecma_get_named_data_property_value (len_prop_p); ecma_number_t *num_p = ecma_get_number_from_value (old_len_value); uint32_t old_len_uint32 = ecma_number_to_uint32 (*num_p); // 3. bool is_property_name_equal_length = ecma_compare_ecma_strings (property_name_p, magic_string_length_p); ecma_deref_ecma_string (magic_string_length_p); if (is_property_name_equal_length) { // a. if (!property_desc_p->is_value_defined) { // i. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } ecma_number_t new_len_num; // c. ecma_value_t completion = ecma_op_to_number (property_desc_p->value); if (ecma_is_value_error (completion)) { return completion; } JERRY_ASSERT (!ecma_is_value_error (completion) && ecma_is_value_number (completion)); new_len_num = *ecma_get_number_from_value (completion); ecma_free_value (completion); uint32_t new_len_uint32 = ecma_number_to_uint32 (new_len_num); // d. if (ecma_uint32_to_number (new_len_uint32) != new_len_num) { return ecma_raise_range_error (""); } else { // b., e. ecma_number_t *new_len_num_p = ecma_alloc_number (); *new_len_num_p = new_len_num; ecma_property_descriptor_t new_len_property_desc = *property_desc_p; new_len_property_desc.value = ecma_make_number_value (new_len_num_p); ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); // f. if (new_len_uint32 >= old_len_uint32) { // i. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ret_value = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); } else { // g. if (!ecma_is_property_writable (len_prop_p)) { ret_value = ecma_reject (is_throw); } else { // h. bool new_writable; if (!new_len_property_desc.is_writable_defined || new_len_property_desc.is_writable) { new_writable = true; } else { // ii. new_writable = false; // iii. new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = true; } // j. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); /* Handling normal false and throw values */ if (!ecma_is_value_true (succeeded)) { JERRY_ASSERT (ecma_is_value_false (succeeded) || ecma_is_value_error (succeeded)); // k. ret_value = succeeded; } else { // l JERRY_ASSERT (new_len_uint32 < old_len_uint32); /* * Item i. is replaced with faster iteration: only indices that actually exist in the array, are iterated */ bool is_reduce_succeeded = true; ecma_collection_header_t *array_index_props_p = ecma_op_object_get_property_names (obj_p, true, false, false); ecma_length_t array_index_props_num = array_index_props_p->unit_number; MEM_DEFINE_LOCAL_ARRAY (array_index_values_p, array_index_props_num, uint32_t); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, array_index_props_p); uint32_t array_index_values_pos = 0; while (ecma_collection_iterator_next (&iter)) { ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); uint32_t index; bool is_index = ecma_string_get_array_index (property_name_p, &index); JERRY_ASSERT (is_index); JERRY_ASSERT (index < old_len_uint32); array_index_values_p[array_index_values_pos++] = index; } JERRY_ASSERT (array_index_values_pos == array_index_props_num); while (array_index_values_pos != 0 && array_index_values_p[--array_index_values_pos] >= new_len_uint32) { uint32_t index = array_index_values_p[array_index_values_pos]; // ii. ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_value_t delete_succeeded = ecma_op_object_delete (obj_p, index_string_p, false); ecma_deref_ecma_string (index_string_p); if (ecma_is_value_false (delete_succeeded)) { // iii. new_len_uint32 = (index + 1u); ecma_number_t *new_len_num_p = ecma_get_number_from_value (new_len_property_desc.value); // 1. *new_len_num_p = ecma_uint32_to_number (index + 1u); // 2. if (!new_writable) { new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = false; } // 3. ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_value_t completion = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_value_boolean (completion)); is_reduce_succeeded = false; break; } } MEM_FINALIZE_LOCAL_ARRAY (array_index_values_p); ecma_free_values_collection (array_index_props_p, true); if (!is_reduce_succeeded) { ret_value = ecma_reject (is_throw); } else { // m. if (!new_writable) { ecma_property_descriptor_t prop_desc_not_writable = ecma_make_empty_property_descriptor (); prop_desc_not_writable.is_writable_defined = true; prop_desc_not_writable.is_writable = false; ecma_value_t completion_set_not_writable; magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); completion_set_not_writable = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &prop_desc_not_writable, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_value_true (completion_set_not_writable)); } ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); } } } } ecma_dealloc_number (new_len_num_p); return ret_value; } JERRY_UNREACHABLE (); } else { // 4.a. uint32_t index; if (!ecma_string_get_array_index (property_name_p, &index)) { // 5. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } // 4. // b. if (index >= old_len_uint32 && !ecma_is_property_writable (len_prop_p)) { return ecma_reject (is_throw); } // c. ecma_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, false); // d. JERRY_ASSERT (ecma_is_value_boolean (succeeded)); if (ecma_is_value_false (succeeded)) { return ecma_reject (is_throw); } // e. if (index >= old_len_uint32) { // i., ii. ecma_number_t *num_p = ecma_alloc_number (); *num_p = ecma_number_add (ecma_uint32_to_number (index), ECMA_NUMBER_ONE); ecma_named_data_property_assign_value (obj_p, len_prop_p, ecma_make_number_value (num_p)); ecma_dealloc_number (num_p); } // f. return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); } JERRY_UNREACHABLE (); } /* ecma_op_array_object_define_own_property */
/** * 'Native call' opcode handler. */ ecma_completion_value_t opfunc_native_call (opcode_t opdata, /**< operation data */ int_data_t *int_data) /**< interpreter context */ { const idx_t dst_var_idx = opdata.data.native_call.lhs; const idx_t native_call_id_idx = opdata.data.native_call.name; const idx_t args_number = opdata.data.native_call.arg_list; const opcode_counter_t lit_oc = int_data->pos; JERRY_ASSERT (native_call_id_idx < OPCODE_NATIVE_CALL__COUNT); int_data->pos++; JERRY_STATIC_ASSERT (OPCODE_NATIVE_CALL__COUNT < (1u << (sizeof (native_call_id_idx) * JERRY_BITSINBYTE))); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); MEM_DEFINE_LOCAL_ARRAY (arg_values, args_number, ecma_value_t); ecma_length_t args_read; ecma_completion_value_t get_arg_completion = fill_varg_list (int_data, args_number, arg_values, &args_read); if (ecma_is_completion_value_empty (get_arg_completion)) { JERRY_ASSERT (args_read == args_number); switch ((opcode_native_call_t)native_call_id_idx) { case OPCODE_NATIVE_CALL_LED_TOGGLE: case OPCODE_NATIVE_CALL_LED_ON: case OPCODE_NATIVE_CALL_LED_OFF: case OPCODE_NATIVE_CALL_LED_ONCE: case OPCODE_NATIVE_CALL_WAIT: { JERRY_UNIMPLEMENTED ("Device operations are not implemented."); } case OPCODE_NATIVE_CALL_PRINT: { for (ecma_length_t arg_index = 0; ecma_is_completion_value_empty (ret_value) && arg_index < args_read; arg_index++) { ECMA_TRY_CATCH (str_value, ecma_op_to_string (arg_values[arg_index]), ret_value); ecma_string_t *str_p = ecma_get_string_from_value (str_value); lit_utf8_size_t bytes = ecma_string_get_size (str_p); ssize_t utf8_str_size = (ssize_t) (bytes + 1); lit_utf8_byte_t *utf8_str_p = (lit_utf8_byte_t*) mem_heap_alloc_block ((size_t) utf8_str_size, MEM_HEAP_ALLOC_SHORT_TERM); if (utf8_str_p == NULL) { jerry_fatal (ERR_OUT_OF_MEMORY); } ecma_string_to_utf8_string (str_p, utf8_str_p, utf8_str_size); utf8_str_p[utf8_str_size - 1] = 0; FIXME ("Support unicode in printf."); if (arg_index < args_read - 1) { printf ("%s ", (char*) utf8_str_p); } else { printf ("%s", (char*) utf8_str_p); } mem_heap_free_block (utf8_str_p); ret_value = set_variable_value (int_data, lit_oc, dst_var_idx, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)); ECMA_FINALIZE (str_value); } printf ("\n"); break; } case OPCODE_NATIVE_CALL__COUNT: { JERRY_UNREACHABLE (); } } } else { JERRY_ASSERT (!ecma_is_completion_value_normal (get_arg_completion)); ret_value = get_arg_completion; } for (ecma_length_t arg_index = 0; arg_index < args_read; arg_index++) { ecma_free_value (arg_values[arg_index], true); } MEM_FINALIZE_LOCAL_ARRAY (arg_values); return ret_value; } /* opfunc_native_call */
/** * Send result of evaluated expression or throw an error. * * @return true - if execution should be resumed * false - otherwise */ static bool jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated string */ size_t eval_string_size) /**< evaluated string size */ { JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE)); JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE); ecma_value_t result = ecma_op_eval_chars_buffer (eval_string_p + 1, eval_string_size - 1, true, false); JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE); if (!ECMA_IS_VALUE_ERROR (result)) { if (eval_string_p[0] != JERRY_DEBUGGER_EVAL_EVAL) { JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); JERRY_CONTEXT (error_value) = result; /* Stop where the error is caught. */ JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; if (eval_string_p[0] == JERRY_DEBUGGER_EVAL_THROW) { JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; } else { JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; } return true; } if (!ecma_is_value_string (result)) { ecma_value_t to_string_value = ecma_op_to_string (result); ecma_free_value (result); result = to_string_value; } } ecma_value_t message = result; uint8_t type = JERRY_DEBUGGER_EVAL_OK; if (ECMA_IS_VALUE_ERROR (result)) { type = JERRY_DEBUGGER_EVAL_ERROR; result = JERRY_CONTEXT (error_value); if (ecma_is_value_object (result)) { message = ecma_op_object_find (ecma_get_object_from_value (result), ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE)); if (!ecma_is_value_string (message) || ecma_string_is_empty (ecma_get_string_from_value (message))) { ecma_free_value (message); lit_magic_string_id_t id = ecma_object_get_class_name (ecma_get_object_from_value (result)); ecma_free_value (result); const lit_utf8_byte_t *string_p = lit_get_magic_string_utf8 (id); jerry_debugger_send_string (JERRY_DEBUGGER_EVAL_RESULT, type, string_p, strlen ((const char *) string_p)); return false; } } else { /* Primitive type. */ message = ecma_op_to_string (result); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (message)); } ecma_free_value (result); } ecma_string_t *string_p = ecma_get_string_from_value (message); ECMA_STRING_TO_UTF8_STRING (string_p, buffer_p, buffer_size); jerry_debugger_send_string (JERRY_DEBUGGER_EVAL_RESULT, type, buffer_p, buffer_size); ECMA_FINALIZE_UTF8_STRING (buffer_p, buffer_size); ecma_free_value (message); return false; } /* jerry_debugger_send_eval */
/** * 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_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 2. */ if (!ecma_op_is_callable (this_arg)) { ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("")); } else { /* 4. 11. 18. */ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); ecma_object_t *function_p = ecma_create_object (prototype_obj_p, false, true, ECMA_OBJECT_TYPE_BOUND_FUNCTION); ecma_deref_object (prototype_obj_p); /* 7. */ ecma_value_t *target_function_prop_p; target_function_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION); ecma_object_t *this_arg_obj_p = ecma_get_object_from_value (this_arg); ECMA_SET_INTERNAL_VALUE_POINTER (*target_function_prop_p, this_arg_obj_p); /* 8. */ ecma_value_t *bound_this_prop_p; bound_this_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS); const ecma_length_t arg_count = arguments_number; if (arg_count > 0) { *bound_this_prop_p = ecma_copy_value_if_not_object (arguments_list_p[0]); } else { *bound_this_prop_p = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } if (arg_count > 1) { ecma_collection_header_t *bound_args_collection_p; bound_args_collection_p = ecma_new_values_collection (&arguments_list_p[1], arg_count - 1, false); ecma_value_t *bound_args_prop_p; bound_args_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS); ECMA_SET_INTERNAL_VALUE_POINTER (*bound_args_prop_p, bound_args_collection_p); } /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type. * * See also: ecma_object_get_class_name */ /* 16. */ ecma_number_t length = ECMA_NUMBER_ZERO; ecma_string_t *magic_string_length_p = ecma_new_ecma_length_string (); /* 15. */ if (ecma_object_get_class_name (this_arg_obj_p) == LIT_MAGIC_STRING_FUNCTION_UL) { ecma_value_t get_len_value = ecma_op_object_get (this_arg_obj_p, magic_string_length_p); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (get_len_value)); JERRY_ASSERT (ecma_is_value_number (get_len_value)); const ecma_length_t bound_arg_count = arg_count > 1 ? arg_count - 1 : 0; /* 15.a */ length = ecma_get_number_from_value (get_len_value) - ((ecma_number_t) bound_arg_count); ecma_free_value (get_len_value); /* 15.b */ if (ecma_number_is_negative (length)) { length = ECMA_NUMBER_ZERO; } } /* 17. */ ecma_value_t completion = ecma_builtin_helper_def_prop (function_p, magic_string_length_p, ecma_make_number_value (length), false, /* Writable */ false, /* Enumerable */ false, /* Configurable */ false); /* Failure handling */ JERRY_ASSERT (ecma_is_value_boolean (completion)); ecma_deref_ecma_string (magic_string_length_p); /* 19-21. */ ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER); ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); { prop_desc.is_enumerable_defined = true; prop_desc.is_enumerable = false; prop_desc.is_configurable_defined = true; prop_desc.is_configurable = false; prop_desc.is_get_defined = true; prop_desc.get_p = thrower_p; prop_desc.is_set_defined = true; prop_desc.set_p = thrower_p; } ecma_string_t *magic_string_caller_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER); completion = ecma_op_object_define_own_property (function_p, magic_string_caller_p, &prop_desc, false); JERRY_ASSERT (ecma_is_value_boolean (completion)); ecma_deref_ecma_string (magic_string_caller_p); ecma_string_t *magic_string_arguments_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); completion = ecma_op_object_define_own_property (function_p, magic_string_arguments_p, &prop_desc, false); JERRY_ASSERT (ecma_is_value_boolean (completion)); ecma_deref_ecma_string (magic_string_arguments_p); ecma_deref_object (thrower_p); /* 22. */ ret_value = ecma_make_object_value (function_p); } return ret_value; } /* ecma_builtin_function_prototype_object_bind */
/** * Update the length of an array to a new length * * @return ecma value * Returned value must be freed with ecma_free_value */ extern ecma_value_t ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object */ ecma_value_t new_value, /**< new length value */ uint32_t flags) /**< configuration options */ { bool is_throw = (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_IS_THROW); ecma_value_t completion = ecma_op_to_number (new_value); if (ECMA_IS_VALUE_ERROR (completion)) { return completion; } JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (completion) && ecma_is_value_number (completion)); ecma_number_t new_len_num = ecma_get_number_from_value (completion); ecma_free_value (completion); if (ecma_is_value_object (new_value)) { ecma_value_t compared_num_val = ecma_op_to_number (new_value); if (ECMA_IS_VALUE_ERROR (completion)) { return compared_num_val; } new_len_num = ecma_get_number_from_value (compared_num_val); ecma_free_value (compared_num_val); } uint32_t new_len_uint32 = ecma_number_to_uint32 (new_len_num); if (((ecma_number_t) new_len_uint32) != new_len_num) { return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid array length.")); } if (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_REJECT) { return ecma_reject (is_throw); } ecma_string_t magic_string_length; ecma_init_ecma_length_string (&magic_string_length); ecma_property_t *len_prop_p = ecma_find_named_property (object_p, &magic_string_length); JERRY_ASSERT (len_prop_p != NULL && ECMA_PROPERTY_GET_TYPE (*len_prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); ecma_property_value_t *len_prop_value_p = ECMA_PROPERTY_VALUE_PTR (len_prop_p); uint32_t old_len_uint32 = ecma_get_uint32_from_value (len_prop_value_p->value); if (new_len_num == old_len_uint32) { /* Only the writable flag must be updated. */ if (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED) { if (!(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE)) { ecma_set_property_writable_attr (len_prop_p, false); } else if (!ecma_is_property_writable (*len_prop_p)) { return ecma_reject (is_throw); } } return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); } else if (!ecma_is_property_writable (*len_prop_p)) { return ecma_reject (is_throw); } uint32_t current_len_uint32 = new_len_uint32; if (new_len_uint32 < old_len_uint32) { current_len_uint32 = ecma_delete_array_properties (object_p, new_len_uint32, old_len_uint32); } ecma_value_assign_uint32 (&len_prop_value_p->value, current_len_uint32); if ((flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED) && !(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE)) { ecma_set_property_writable_attr (len_prop_p, false); } if (current_len_uint32 == new_len_uint32) { return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); } return ecma_reject (is_throw); } /* ecma_op_array_object_set_length */
/** * The processor for PromiseReactionJob. * * See also: ES2015 25.4.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value */ static ecma_value_t ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */ { ecma_job_promise_reaction_t *job_p = (ecma_job_promise_reaction_t *) obj_p; ecma_object_t *reaction_p = ecma_get_object_from_value (job_p->reaction); ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); ecma_string_t *str_handler = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_HANDLER); ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); /* 2. */ ecma_value_t capability = ecma_op_object_get (reaction_p, str_capability); /* 3. */ ecma_value_t handler = ecma_op_object_get (reaction_p, str_handler); JERRY_ASSERT (ecma_is_value_boolean (handler) || ecma_op_is_callable (handler)); ecma_value_t handler_result; if (ecma_is_value_boolean (handler)) { /* 4-5. True indicates "identity" and false indicates "thrower" */ handler_result = ecma_copy_value (job_p->argument); } else { /* 6. */ handler_result = ecma_op_function_call (ecma_get_object_from_value (handler), ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), &(job_p->argument), 1); } ecma_value_t status; if (ecma_is_value_false (handler) || ECMA_IS_VALUE_ERROR (handler_result)) { if (ECMA_IS_VALUE_ERROR (handler_result)) { handler_result = ecma_get_value_from_error_value (handler_result); } /* 7. */ ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_reject); JERRY_ASSERT (ecma_op_is_callable (reject)); status = ecma_op_function_call (ecma_get_object_from_value (reject), ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), &handler_result, 1); ecma_free_value (reject); } else { /* 8. */ ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), str_resolve); JERRY_ASSERT (ecma_op_is_callable (resolve)); status = ecma_op_function_call (ecma_get_object_from_value (resolve), ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), &handler_result, 1); ecma_free_value (resolve); } ecma_free_value (handler_result); ecma_free_value (handler); ecma_free_value (capability); ecma_deref_ecma_string (str_capability); ecma_deref_ecma_string (str_handler); ecma_deref_ecma_string (str_resolve); ecma_deref_ecma_string (str_reject); ecma_free_promise_reaction_job (job_p); return status; } /* ecma_process_promise_reaction_job */
/** * The Function.prototype object's 'apply' routine * * See also: * ECMA-262 v5, 15.3.4.3 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_function_prototype_object_apply (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg1, /**< first argument */ ecma_value_t arg2) /**< second argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ if (!ecma_op_is_callable (this_arg)) { ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("")); } else { ecma_object_t *func_obj_p = ecma_get_object_from_value (this_arg); /* 2. */ if (ecma_is_value_null (arg2) || ecma_is_value_undefined (arg2)) { ret_value = ecma_op_function_call (func_obj_p, arg1, NULL, 0); } else { /* 3. */ if (!ecma_is_value_object (arg2)) { ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("")); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg2); ecma_string_t *length_magic_string_p = ecma_new_ecma_length_string (); /* 4. */ ECMA_TRY_CATCH (length_value, ecma_op_object_get (obj_p, length_magic_string_p), ret_value); ECMA_OP_TO_NUMBER_TRY_CATCH (length_number, length_value, ret_value); /* 5. */ const uint32_t length = ecma_number_to_uint32 (length_number); /* 6. */ JMEM_DEFINE_LOCAL_ARRAY (arguments_list_p, length, ecma_value_t); uint32_t last_index = 0; /* 7. */ for (uint32_t index = 0; index < length && ecma_is_value_empty (ret_value); index++) { ecma_string_t *curr_idx_str_p = ecma_new_ecma_string_from_uint32 (index); ECMA_TRY_CATCH (get_value, ecma_op_object_get (obj_p, curr_idx_str_p), ret_value); arguments_list_p[index] = ecma_copy_value (get_value); last_index = index + 1; ECMA_FINALIZE (get_value); ecma_deref_ecma_string (curr_idx_str_p); } if (ecma_is_value_empty (ret_value)) { JERRY_ASSERT (last_index == length); ret_value = ecma_op_function_call (func_obj_p, arg1, arguments_list_p, length); } for (uint32_t index = 0; index < last_index; index++) { ecma_free_value (arguments_list_p[index]); } JMEM_FINALIZE_LOCAL_ARRAY (arguments_list_p); ECMA_OP_TO_NUMBER_FINALIZE (length_number); ECMA_FINALIZE (length_value); ecma_deref_ecma_string (length_magic_string_p); } } } return ret_value; } /* ecma_builtin_function_prototype_object_apply */
/** * The Error.prototype object's 'toString' routine * * See also: * ECMA-262 v5, 15.11.4.4 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_error_prototype_object_to_string (ecma_value_t this_arg) /**< this argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); // 2. if (!ecma_is_value_object (this_arg)) { ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("")); } else { ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); ecma_string_t *name_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAME); ECMA_TRY_CATCH (name_get_ret_value, ecma_op_object_get (obj_p, name_magic_string_p), ret_value); ecma_value_t name_to_str_completion; if (ecma_is_value_undefined (name_get_ret_value)) { ecma_string_t *error_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ERROR_UL); name_to_str_completion = ecma_make_string_value (error_magic_string_p); } else { name_to_str_completion = ecma_op_to_string (name_get_ret_value); } if (unlikely (ecma_is_value_error (name_to_str_completion))) { ret_value = ecma_copy_value (name_to_str_completion); } else { ecma_string_t *message_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE); ECMA_TRY_CATCH (msg_get_ret_value, ecma_op_object_get (obj_p, message_magic_string_p), ret_value); ecma_value_t msg_to_str_completion; if (ecma_is_value_undefined (msg_get_ret_value)) { ecma_string_t *empty_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); msg_to_str_completion = ecma_make_string_value (empty_magic_string_p); } else { msg_to_str_completion = ecma_op_to_string (msg_get_ret_value); } if (unlikely (ecma_is_value_error (msg_to_str_completion))) { ret_value = ecma_copy_value (msg_to_str_completion); } else { ecma_string_t *name_string_p = ecma_get_string_from_value (name_to_str_completion); ecma_string_t *msg_string_p = ecma_get_string_from_value (msg_to_str_completion); ecma_string_t *ret_str_p; if (ecma_string_get_length (name_string_p) == 0) { ret_str_p = ecma_copy_or_ref_ecma_string (msg_string_p); } else if (ecma_string_get_length (msg_string_p) == 0) { ret_str_p = ecma_copy_or_ref_ecma_string (name_string_p); } else { const lit_utf8_size_t name_size = ecma_string_get_size (name_string_p); const lit_utf8_size_t msg_size = ecma_string_get_size (msg_string_p); const lit_utf8_size_t colon_size = lit_get_magic_string_size (LIT_MAGIC_STRING_COLON_CHAR); const lit_utf8_size_t space_size = lit_get_magic_string_size (LIT_MAGIC_STRING_SPACE_CHAR); const lit_utf8_size_t size = name_size + msg_size + colon_size + space_size; JMEM_DEFINE_LOCAL_ARRAY (ret_str_buffer, size, lit_utf8_byte_t); lit_utf8_byte_t *ret_str_buffer_p = ret_str_buffer; lit_utf8_size_t bytes = ecma_string_to_utf8_string (name_string_p, ret_str_buffer_p, name_size); JERRY_ASSERT (bytes == name_size); ret_str_buffer_p = ret_str_buffer_p + bytes; JERRY_ASSERT (ret_str_buffer_p <= ret_str_buffer + size); ret_str_buffer_p = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_COLON_CHAR, ret_str_buffer_p, colon_size); JERRY_ASSERT (ret_str_buffer_p <= ret_str_buffer + size); ret_str_buffer_p = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_SPACE_CHAR, ret_str_buffer_p, space_size); JERRY_ASSERT (ret_str_buffer_p <= ret_str_buffer + size); bytes = ecma_string_to_utf8_string (msg_string_p, ret_str_buffer_p, msg_size); JERRY_ASSERT (bytes == msg_size); ret_str_buffer_p = ret_str_buffer_p + bytes; JERRY_ASSERT (ret_str_buffer_p == ret_str_buffer + size); ret_str_p = ecma_new_ecma_string_from_utf8 (ret_str_buffer, size); JMEM_FINALIZE_LOCAL_ARRAY (ret_str_buffer); } ret_value = ecma_make_string_value (ret_str_p); } ecma_free_value (msg_to_str_completion); ECMA_FINALIZE (msg_get_ret_value); ecma_deref_ecma_string (message_magic_string_p); } ecma_free_value (name_to_str_completion); ECMA_FINALIZE (name_get_ret_value); ecma_deref_ecma_string (name_magic_string_p); } return ret_value; } /* ecma_builtin_error_prototype_object_to_string */