/** * Perform 'eval' with code stored in ecma-string * * See also: * ecma_op_eval_chars_buffer * ECMA-262 v5, 15.1.2.1 (steps 2 to 8) * * @return completion value */ ecma_completion_value_t ecma_op_eval (ecma_string_t *code_p, /**< code string */ bool is_direct, /**< is eval called directly (ECMA-262 v5, 15.1.2.1.1) */ bool is_called_from_strict_mode_code) /**< is eval is called from strict mode code */ { ecma_completion_value_t ret_value; lit_utf8_size_t chars_num = ecma_string_get_size (code_p); if (chars_num == 0) { ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)); } else { MEM_DEFINE_LOCAL_ARRAY (code_utf8_buffer_p, chars_num, lit_utf8_byte_t); const ssize_t buf_size = (ssize_t) chars_num; ssize_t buffer_size_req = ecma_string_to_utf8_string (code_p, code_utf8_buffer_p, buf_size); JERRY_ASSERT (buffer_size_req == buf_size); ret_value = ecma_op_eval_chars_buffer ((jerry_api_char_t *) code_utf8_buffer_p, (size_t) buf_size, is_direct, is_called_from_strict_mode_code); MEM_FINALIZE_LOCAL_ARRAY (code_utf8_buffer_p); } return ret_value; } /* ecma_op_eval */
/** * Allocate a collection of ecma-strings. * * @return pointer to the collection's header */ ecma_collection_header_t * ecma_new_strings_collection (ecma_string_t *string_ptrs_buffer[], /**< pointers to ecma-strings */ ecma_length_t strings_number) /**< number of ecma-strings */ { JERRY_ASSERT (string_ptrs_buffer != NULL); JERRY_ASSERT (strings_number > 0); ecma_collection_header_t *new_collection_p; MEM_DEFINE_LOCAL_ARRAY (values_buffer, strings_number, ecma_value_t); for (ecma_length_t string_index = 0; string_index < strings_number; string_index++) { values_buffer[string_index] = ecma_make_string_value (string_ptrs_buffer[string_index]); } new_collection_p = ecma_new_values_collection (values_buffer, strings_number, false); MEM_FINALIZE_LOCAL_ARRAY (values_buffer); return new_collection_p; } /* ecma_new_strings_collection */
/** * Run the code, starting from specified instruction position */ ecma_completion_value_t vm_run_from_pos (const vm_instr_t *instrs_p, /**< byte-code array */ vm_instr_counter_t start_pos, /**< position of starting instruction */ ecma_value_t this_binding_value, /**< value of 'ThisBinding' */ ecma_object_t *lex_env_p, /**< lexical environment to use */ bool is_strict, /**< is the code is strict mode code (ECMA-262 v5, 10.1.1) */ bool is_eval_code) /**< is the code is eval code (ECMA-262 v5, 10.1) */ { ecma_completion_value_t completion; const vm_instr_t *curr = &instrs_p[start_pos]; JERRY_ASSERT (curr->op_idx == VM_OP_REG_VAR_DECL); const idx_t min_reg_num = curr->data.reg_var_decl.min; const idx_t max_reg_num = curr->data.reg_var_decl.max; JERRY_ASSERT (max_reg_num >= min_reg_num); const int32_t regs_num = max_reg_num - min_reg_num + 1; MEM_DEFINE_LOCAL_ARRAY (regs, regs_num, ecma_value_t); vm_frame_ctx_t frame_ctx; frame_ctx.instrs_p = instrs_p; frame_ctx.pos = (vm_instr_counter_t) (start_pos + 1); frame_ctx.this_binding = this_binding_value; frame_ctx.lex_env_p = lex_env_p; frame_ctx.is_strict = is_strict; frame_ctx.is_eval_code = is_eval_code; frame_ctx.is_call_in_direct_eval_form = false; frame_ctx.min_reg_num = min_reg_num; frame_ctx.max_reg_num = max_reg_num; frame_ctx.tmp_num_p = ecma_alloc_number (); vm_stack_add_frame (&frame_ctx.stack_frame, regs, regs_num); vm_frame_ctx_t *prev_context_p = vm_top_context_p; vm_top_context_p = &frame_ctx; #ifdef MEM_STATS interp_mem_stats_context_enter (&frame_ctx, start_pos); #endif /* MEM_STATS */ completion = vm_loop (&frame_ctx, NULL); JERRY_ASSERT (ecma_is_completion_value_throw (completion) || ecma_is_completion_value_return (completion)); vm_top_context_p = prev_context_p; vm_stack_free_frame (&frame_ctx.stack_frame); ecma_dealloc_number (frame_ctx.tmp_num_p); #ifdef MEM_STATS interp_mem_stats_context_exit (&frame_ctx, start_pos); #endif /* MEM_STATS */ MEM_FINALIZE_LOCAL_ARRAY (regs); return completion; } /* vm_run_from_pos */
/** * Run the code, starting from specified opcode */ ecma_completion_value_t vm_run_from_pos (opcode_counter_t start_pos, /**< identifier of starting opcode */ ecma_value_t this_binding_value, /**< value of 'ThisBinding' */ ecma_object_t *lex_env_p, /**< lexical environment to use */ bool is_strict, /**< is the code is strict mode code (ECMA-262 v5, 10.1.1) */ bool is_eval_code) /**< is the code is eval code (ECMA-262 v5, 10.1) */ { ecma_completion_value_t completion; const opcode_t *curr = &__program[start_pos]; JERRY_ASSERT (curr->op_idx == __op__idx_reg_var_decl); const idx_t min_reg_num = curr->data.reg_var_decl.min; const idx_t max_reg_num = curr->data.reg_var_decl.max; JERRY_ASSERT (max_reg_num >= min_reg_num); const int32_t regs_num = max_reg_num - min_reg_num + 1; MEM_DEFINE_LOCAL_ARRAY (regs, regs_num, ecma_value_t); int_data_t int_data; int_data.pos = (opcode_counter_t) (start_pos + 1); int_data.this_binding = this_binding_value; int_data.lex_env_p = lex_env_p; int_data.is_strict = is_strict; int_data.is_eval_code = is_eval_code; int_data.min_reg_num = min_reg_num; int_data.max_reg_num = max_reg_num; int_data.tmp_num_p = ecma_alloc_number (); ecma_stack_add_frame (&int_data.stack_frame, regs, regs_num); int_data_t *prev_context_p = vm_top_context_p; vm_top_context_p = &int_data; #ifdef MEM_STATS interp_mem_stats_context_enter (&int_data, start_pos); #endif /* MEM_STATS */ completion = vm_loop (&int_data, NULL); JERRY_ASSERT (ecma_is_completion_value_normal (completion) || ecma_is_completion_value_throw (completion) || ecma_is_completion_value_return (completion) || ecma_is_completion_value_exit (completion)); vm_top_context_p = prev_context_p; ecma_stack_free_frame (&int_data.stack_frame); ecma_dealloc_number (int_data.tmp_num_p); #ifdef MEM_STATS interp_mem_stats_context_exit (&int_data, start_pos); #endif /* MEM_STATS */ MEM_FINALIZE_LOCAL_ARRAY (regs); return completion; } /* vm_run_from_pos */
/** * Parse RegExp flags (global, ignoreCase, multiline) * * See also: ECMA-262 v5, 15.10.4.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t re_parse_regexp_flags (ecma_string_t *flags_str_p, /**< Input string with flags */ uint8_t *flags_p) /**< Output: parsed flag bits */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); lit_utf8_size_t flags_str_size = ecma_string_get_size (flags_str_p); MEM_DEFINE_LOCAL_ARRAY (flags_start_p, flags_str_size, lit_utf8_byte_t); ecma_string_to_utf8_string (flags_str_p, flags_start_p, (ssize_t) flags_str_size); lit_utf8_iterator_t iter = lit_utf8_iterator_create (flags_start_p, flags_str_size); while (!lit_utf8_iterator_is_eos (&iter) && ecma_is_completion_value_empty (ret_value)) { switch (lit_utf8_iterator_read_next (&iter)) { case 'g': { if (*flags_p & RE_FLAG_GLOBAL) { ret_value = ecma_raise_syntax_error ("Invalid RegExp flags."); } *flags_p |= RE_FLAG_GLOBAL; break; } case 'i': { if (*flags_p & RE_FLAG_IGNORE_CASE) { ret_value = ecma_raise_syntax_error ("Invalid RegExp flags."); } *flags_p |= RE_FLAG_IGNORE_CASE; break; } case 'm': { if (*flags_p & RE_FLAG_MULTILINE) { ret_value = ecma_raise_syntax_error ("Invalid RegExp flags."); } *flags_p |= RE_FLAG_MULTILINE; break; } default: { ret_value = ecma_raise_syntax_error ("Invalid RegExp flags."); break; } } } MEM_FINALIZE_LOCAL_ARRAY (flags_start_p); return ret_value; } /* re_parse_regexp_flags */
/** * The String object's 'fromCharCode' routine * * See also: * ECMA-262 v5, 15.5.3.2 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_string_object_from_char_code (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ const ecma_value_t args[], /**< arguments list */ ecma_length_t args_number) /**< number of arguments */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); if (args_number == 0) { ecma_string_t *ret_str_p = ecma_new_ecma_string_from_utf8 (NULL, 0); return ecma_make_normal_completion_value (ecma_make_string_value (ret_str_p)); } lit_utf8_size_t utf8_buf_size = args_number * LIT_UTF8_MAX_BYTES_IN_CODE_UNIT; ecma_string_t *ret_str_p; MEM_DEFINE_LOCAL_ARRAY (utf8_buf_p, utf8_buf_size, lit_utf8_byte_t); lit_utf8_size_t utf8_buf_used = 0; FIXME ("Support surrogate pairs"); for (ecma_length_t arg_index = 0; arg_index < args_number; arg_index++) { ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, args[arg_index], ret_value); uint32_t uint32_char_code = ecma_number_to_uint32 (arg_num); ecma_char_t code_unit = (uint16_t) uint32_char_code; JERRY_ASSERT (utf8_buf_used <= utf8_buf_size - LIT_UTF8_MAX_BYTES_IN_CODE_UNIT); utf8_buf_used += lit_code_unit_to_utf8 (code_unit, utf8_buf_p + utf8_buf_used); JERRY_ASSERT (utf8_buf_used <= utf8_buf_size); ECMA_OP_TO_NUMBER_FINALIZE (arg_num); if (ecma_is_completion_value_throw (ret_value)) { mem_heap_free_block (utf8_buf_p); return ret_value; } JERRY_ASSERT (ecma_is_completion_value_empty (ret_value)); } ret_str_p = ecma_new_ecma_string_from_utf8 (utf8_buf_p, utf8_buf_used); MEM_FINALIZE_LOCAL_ARRAY (utf8_buf_p); return ecma_make_normal_completion_value (ecma_make_string_value (ret_str_p)); } /* ecma_builtin_string_object_from_char_code */
/** * Convert decimal value to 4 digit hexadecimal string value. * * See also: * ECMA-262 v5, 15.12.3 * * Used by: * - ecma_builtin_json_quote step 2.c.iii * * @return pointer to ecma-string * Returned value must be freed with ecma_deref_ecma_string. */ ecma_string_t * ecma_builtin_helper_json_create_hex_digit_ecma_string (uint8_t value) /**< value in decimal*/ { /* 2.c.iii */ ecma_string_t *hex_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); MEM_DEFINE_LOCAL_ARRAY (hex_buff, 4, lit_utf8_byte_t); for (uint32_t i = 0; i < 4; i++) { uint8_t remainder = value % 16; lit_utf8_byte_t ch = ' '; if (remainder < 10) { ch = (lit_utf8_byte_t) (LIT_CHAR_0 + remainder); } else { uint8_t a = (uint8_t) (remainder - 10); ch = (lit_utf8_byte_t) (LIT_CHAR_LOWERCASE_A + a); } hex_buff[3 - i] = ch; value = value / 16; } ecma_deref_ecma_string (hex_str_p); hex_str_p = ecma_new_ecma_string_from_utf8 ((lit_utf8_byte_t *) hex_buff, 4); MEM_FINALIZE_LOCAL_ARRAY (hex_buff); JERRY_ASSERT (ecma_string_get_length (hex_str_p)); return hex_str_p; } /* ecma_builtin_helper_json_create_hex_digit_ecma_string */
/** * The Date object's 'parse' routine * * See also: * ECMA-262 v5, 15.9.4.2 * ECMA-262 v5, 15.9.1.15 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_date_parse (ecma_value_t this_arg __attr_unused___, /**< this argument */ ecma_value_t arg) /**< string */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ecma_number_t *date_num_p = ecma_alloc_number (); *date_num_p = ecma_number_make_nan (); /* Date Time String fromat (ECMA-262 v5, 15.9.1.15) */ ECMA_TRY_CATCH (date_str_value, ecma_op_to_string (arg), ret_value); ecma_string_t *date_str_p = ecma_get_string_from_value (date_str_value); lit_utf8_size_t date_str_size = ecma_string_get_size (date_str_p); MEM_DEFINE_LOCAL_ARRAY (date_start_p, date_str_size, lit_utf8_byte_t); ssize_t sz = ecma_string_to_utf8_string (date_str_p, date_start_p, (ssize_t) date_str_size); JERRY_ASSERT (sz >= 0); lit_utf8_byte_t *date_str_curr_p = date_start_p; const lit_utf8_byte_t *date_str_end_p = date_start_p + date_str_size; /* 1. read year */ ecma_number_t year = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 4); if (!ecma_number_is_nan (year) && year >= 0) { ecma_number_t month = ECMA_NUMBER_ONE; ecma_number_t day = ECMA_NUMBER_ONE; ecma_number_t time = ECMA_NUMBER_ZERO; /* 2. read month if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == '-') { /* eat up '-' */ date_str_curr_p++; month = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (month > 12 || month < 1) { month = ecma_number_make_nan (); } } /* 3. read day if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == '-') { /* eat up '-' */ date_str_curr_p++; day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (day < 1 || day > 31) { day = ecma_number_make_nan (); } } /* 4. read time if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == 'T') { /* eat up 'T' */ date_str_curr_p++; ecma_number_t hours = ECMA_NUMBER_ZERO; ecma_number_t minutes = ECMA_NUMBER_ZERO; ecma_number_t seconds = ECMA_NUMBER_ZERO; ecma_number_t milliseconds = ECMA_NUMBER_ZERO; ecma_length_t remaining_length = lit_utf8_string_length (date_str_curr_p, (lit_utf8_size_t) (date_str_end_p - date_str_curr_p)); if (remaining_length >= 5) { /* 4.1 read hours and minutes */ hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (hours < 0 || hours > 24) { hours = ecma_number_make_nan (); } else if (hours == 24) { hours = ECMA_NUMBER_ZERO; } /* eat up ':' */ date_str_curr_p++; minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (minutes < 0 || minutes > 59) { minutes = ecma_number_make_nan (); } /* 4.2 read seconds if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == ':') { /* eat up ':' */ date_str_curr_p++; seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (seconds < 0 || seconds > 59) { seconds = ecma_number_make_nan (); } /* 4.3 read milliseconds if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == '.') { /* eat up '.' */ date_str_curr_p++; milliseconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 3); if (milliseconds < 0) { milliseconds = ecma_number_make_nan (); } } } time = ecma_date_make_time (hours, minutes, seconds, milliseconds); } else { time = ecma_number_make_nan (); } /* 4.4 read timezone if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == 'Z' && !ecma_number_is_nan (time)) { date_str_curr_p++; time = ecma_date_make_time (hours, minutes, seconds, milliseconds); } else if (date_str_curr_p < date_str_end_p && (*date_str_curr_p == '+' || *date_str_curr_p == '-')) { ecma_length_t remaining_length; remaining_length = lit_utf8_string_length (date_str_curr_p, (lit_utf8_size_t) (date_str_end_p - date_str_curr_p)) - 1; if (remaining_length == 5) { bool is_negative = false; if (*date_str_curr_p == '-') { is_negative = true; } /* eat up '+/-' */ date_str_curr_p++; /* read hours and minutes */ hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (hours < 0 || hours > 24) { hours = ecma_number_make_nan (); } else if (hours == 24) { hours = ECMA_NUMBER_ZERO; } /* eat up ':' */ date_str_curr_p++; minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (minutes < 0 || minutes > 59) { minutes = ecma_number_make_nan (); } if (is_negative) { time += ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); } else { time -= ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); } } } } if (date_str_curr_p >= date_str_end_p) { ecma_number_t date = ecma_date_make_day (year, month - 1, day); *date_num_p = ecma_date_make_date (date, time); } } ret_value = ecma_make_normal_completion_value (ecma_make_number_value (date_num_p)); MEM_FINALIZE_LOCAL_ARRAY (date_start_p); ECMA_FINALIZE (date_str_value); return ret_value; } /* ecma_builtin_date_parse */
/** * The Number.prototype object's 'toExponential' routine * * See also: * ECMA-262 v5, 15.7.4.6 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_to_exponential (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ ECMA_TRY_CATCH (this_value, ecma_builtin_number_prototype_object_value_of (this_arg), ret_value); ecma_number_t this_num = *ecma_get_number_from_value (this_value); ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value); /* 7. */ if (arg_num <= -1.0 || arg_num >= 21.0) { ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("")); } else { /* 3. */ if (ecma_number_is_nan (this_num)) { ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); ret_value = ecma_make_string_value (nan_str_p); } else { bool is_negative = false; /* 5. */ if (ecma_number_is_negative (this_num) && !ecma_number_is_zero (this_num)) { is_negative = true; this_num *= -1; } /* 6. */ if (ecma_number_is_infinity (this_num)) { ecma_string_t *infinity_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INFINITY_UL); if (is_negative) { ecma_string_t *neg_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_MINUS_CHAR); ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p); ecma_deref_ecma_string (infinity_str_p); ecma_deref_ecma_string (neg_str_p); ret_value = ecma_make_string_value (neg_inf_str_p); } else { ret_value = ecma_make_string_value (infinity_str_p); } } else { uint64_t digits = 0; int32_t num_digits = 0; int32_t exponent = 1; if (!ecma_number_is_zero (this_num)) { /* Get the parameters of the number if non zero. */ ecma_number_to_decimal (this_num, &digits, &num_digits, &exponent); } int32_t frac_digits; if (ecma_is_value_undefined (arg)) { frac_digits = num_digits - 1; } else { frac_digits = ecma_number_to_int32 (arg_num); } digits = ecma_builtin_number_prototype_helper_round (digits, num_digits - frac_digits - 1); /* frac_digits + 2 characters for number, 5 characters for exponent, 1 for \0. */ int buffer_size = frac_digits + 2 + 5 + 1; if (is_negative) { /* +1 character for sign. */ buffer_size++; } MEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, lit_utf8_byte_t); int digit = 0; uint64_t scale = 1; /* Calculate the magnitude of the number. This is used to get the digits from left to right. */ while (scale <= digits) { scale *= 10; } lit_utf8_byte_t *actual_char_p = buff; if (is_negative) { *actual_char_p++ = '-'; } /* Add significant digits. */ for (int i = 0; i <= frac_digits; i++) { digit = 0; scale /= 10; while (digits >= scale && scale > 0) { digits -= scale; digit++; } *actual_char_p = (lit_utf8_byte_t) (digit + '0'); actual_char_p++; if (i == 0 && frac_digits != 0) { *actual_char_p++ = '.'; } } *actual_char_p++ = 'e'; exponent--; if (exponent < 0) { exponent *= -1; *actual_char_p++ = '-'; } else { *actual_char_p++ = '+'; } /* Get magnitude of exponent. */ int32_t scale_expt = 1; while (scale_expt <= exponent) { scale_expt *= 10; } scale_expt /= 10; /* Add exponent digits. */ if (exponent == 0) { *actual_char_p++ = '0'; } else { while (scale_expt > 0) { digit = exponent / scale_expt; exponent %= scale_expt; *actual_char_p++ = (lit_utf8_byte_t) (digit + '0'); scale_expt /= 10; } } JERRY_ASSERT (actual_char_p - buff < buffer_size); *actual_char_p = '\0'; ecma_string_t *str = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) (actual_char_p - buff)); ret_value = ecma_make_string_value (str); MEM_FINALIZE_LOCAL_ARRAY (buff); } } } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); ECMA_FINALIZE (this_value); return ret_value; } /* ecma_builtin_number_prototype_object_to_exponential */
/** * The Date object's 'parse' routine * * See also: * ECMA-262 v5, 15.9.4.2 * ECMA-262 v5, 15.9.1.15 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_date_parse (ecma_value_t this_arg __attr_unused___, /**< this argument */ ecma_value_t arg) /**< string */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ecma_number_t *date_num_p = ecma_alloc_number (); *date_num_p = ecma_number_make_nan (); /* Date Time String fromat (ECMA-262 v5, 15.9.1.15) */ ECMA_TRY_CATCH (date_str_value, ecma_op_to_string (arg), ret_value); ecma_string_t *date_str_p = ecma_get_string_from_value (date_str_value); lit_utf8_size_t date_str_size = ecma_string_get_size (date_str_p); MEM_DEFINE_LOCAL_ARRAY (date_start_p, date_str_size, lit_utf8_byte_t); ecma_string_to_utf8_string (date_str_p, date_start_p, (ssize_t) date_str_size); lit_utf8_iterator_t iter = lit_utf8_iterator_create (date_start_p, date_str_size); /* 1. read year */ ecma_number_t year = ecma_date_parse_date_chars (&iter, 4); if (!ecma_number_is_nan (year) && year >= 0) { ecma_number_t month = ECMA_NUMBER_ONE; ecma_number_t day = ECMA_NUMBER_ONE; ecma_number_t time = ECMA_NUMBER_ZERO; /* 2. read month if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == '-') { /* eat up '-' */ lit_utf8_iterator_incr (&iter); month = ecma_date_parse_date_chars (&iter, 2); if (month > 12 || month < 1) { month = ecma_number_make_nan (); } } /* 3. read day if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == '-') { /* eat up '-' */ lit_utf8_iterator_incr (&iter); day = ecma_date_parse_date_chars (&iter, 2); if (day < 1 || day > 31) { day = ecma_number_make_nan (); } } /* 4. read time if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == 'T') { ecma_number_t hours = ECMA_NUMBER_ZERO; ecma_number_t minutes = ECMA_NUMBER_ZERO; ecma_number_t seconds = ECMA_NUMBER_ZERO; ecma_number_t milliseconds = ECMA_NUMBER_ZERO; ecma_length_t num_of_visited_chars = lit_utf8_iterator_get_index (&iter); ecma_length_t date_str_len = lit_utf8_string_length (iter.buf_p, iter.buf_size) - 1; if ((date_str_len - num_of_visited_chars) >= 5) { /* eat up 'T' */ lit_utf8_iterator_incr (&iter); /* 4.1 read hours and minutes */ hours = ecma_date_parse_date_chars (&iter, 2); if (hours < 0 || hours > 24) { hours = ecma_number_make_nan (); } else if (hours == 24) { hours = ECMA_NUMBER_ZERO; } /* eat up ':' */ lit_utf8_iterator_incr (&iter); minutes = ecma_date_parse_date_chars (&iter, 2); if (minutes < 0 || minutes > 59) { minutes = ecma_number_make_nan (); } /* 4.2 read seconds if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == ':') { /* eat up ':' */ lit_utf8_iterator_incr (&iter); seconds = ecma_date_parse_date_chars (&iter, 2); if (seconds < 0 || seconds > 59) { seconds = ecma_number_make_nan (); } /* 4.3 read milliseconds if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == '.') { /* eat up '.' */ lit_utf8_iterator_incr (&iter); milliseconds = ecma_date_parse_date_chars (&iter, 3); if (milliseconds < 0) { milliseconds = ecma_number_make_nan (); } } } time = ecma_date_make_time (hours, minutes, seconds, milliseconds); } else { time = ecma_number_make_nan (); } /* 4.4 read timezone if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == 'Z' && !ecma_number_is_nan (time)) { lit_utf8_iterator_incr (&iter); time = ecma_date_utc (ecma_date_make_time (hours, minutes, seconds, milliseconds)); } else if (!lit_utf8_iterator_is_eos (&iter) && (lit_utf8_iterator_peek_next (&iter) == '+' || lit_utf8_iterator_peek_next (&iter) == '-')) { ecma_length_t num_of_visited_chars = lit_utf8_iterator_get_index (&iter); ecma_length_t date_str_len = lit_utf8_string_length (iter.buf_p, iter.buf_size) - 1; if ((date_str_len - num_of_visited_chars) == 5) { bool is_negative = false; if (lit_utf8_iterator_peek_next (&iter) == '-') { is_negative = true; } /* eat up '+/-' */ lit_utf8_iterator_incr (&iter); /* read hours and minutes */ hours = ecma_date_parse_date_chars (&iter, 2); if (hours < 0 || hours > 24) { hours = ecma_number_make_nan (); } else if (hours == 24) { hours = ECMA_NUMBER_ZERO; } /* eat up ':' */ lit_utf8_iterator_incr (&iter); minutes = ecma_date_parse_date_chars (&iter, 2); if (minutes < 0 || minutes > 59) { minutes = ecma_number_make_nan (); } if (is_negative) { time += ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); } else { time -= ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); } } } } if (lit_utf8_iterator_is_eos (&iter)) { ecma_number_t date = ecma_date_make_day (year, month - 1, day); *date_num_p = ecma_date_make_date (date, time); } } ret_value = ecma_make_normal_completion_value (ecma_make_number_value (date_num_p)); MEM_FINALIZE_LOCAL_ARRAY (date_start_p); ECMA_FINALIZE (date_str_value); return ret_value; } /* ecma_builtin_date_parse */
/** * The Number.prototype object's 'toPrecision' routine * * See also: * ECMA-262 v5, 15.7.4.7 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_to_precision (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ ECMA_TRY_CATCH (this_value, ecma_builtin_number_prototype_object_value_of (this_arg), ret_value); ecma_number_t this_num = *ecma_get_number_from_value (this_value); /* 2. */ if (ecma_is_value_undefined (arg)) { ret_value = ecma_builtin_number_prototype_object_to_string (this_arg, NULL, 0); } else { /* 3. */ ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value); /* 4. */ if (ecma_number_is_nan (this_num)) { ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); ret_value = ecma_make_string_value (nan_str_p); } else { bool is_negative = false; /* 6. */ if (ecma_number_is_negative (this_num) && !ecma_number_is_zero (this_num)) { is_negative = true; this_num *= -1; } /* 7. */ if (ecma_number_is_infinity (this_num)) { ecma_string_t *infinity_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INFINITY_UL); if (is_negative) { ecma_string_t *neg_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_MINUS_CHAR); ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p); ecma_deref_ecma_string (infinity_str_p); ecma_deref_ecma_string (neg_str_p); ret_value = ecma_make_string_value (neg_inf_str_p); } else { ret_value = ecma_make_string_value (infinity_str_p); } } /* 8. */ else if (arg_num < 1.0 || arg_num >= 22.0) { ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("")); } else { uint64_t digits = 0; int32_t num_digits = 0; int32_t exponent = 1; int32_t precision = ecma_number_to_int32 (arg_num); /* Get the parameters of the number if non-zero. */ if (!ecma_number_is_zero (this_num)) { ecma_number_to_decimal (this_num, &digits, &num_digits, &exponent); } digits = ecma_builtin_number_prototype_helper_round (digits, num_digits - precision); int buffer_size; if (exponent < -5 || exponent > precision) { /* Exponential notation, precision + 1 digits for number, 5 for exponent, 1 for \0 */ buffer_size = precision + 1 + 5 + 1; } else if (exponent <= 0) { /* Fixed notation, -exponent + 2 digits for leading zeros, precision digits, 1 for \0 */ buffer_size = -exponent + 2 + precision + 1; } else { /* Fixed notation, precision + 1 digits for number, 1 for \0 */ buffer_size = precision + 1 + 1; } if (is_negative) { buffer_size++; } MEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, lit_utf8_byte_t); lit_utf8_byte_t *actual_char_p = buff; uint64_t scale = 1; /* Calculate the magnitude of the number. This is used to get the digits from left to right. */ while (scale <= digits) { scale *= 10; } if (is_negative) { *actual_char_p++ = '-'; } int digit = 0; /* 10.c, Exponential notation.*/ if (exponent < -5 || exponent > precision) { /* Add significant digits. */ for (int i = 1; i <= precision; i++) { digit = 0; scale /= 10; while (digits >= scale && scale > 0) { digits -= scale; digit++; } *actual_char_p++ = (lit_utf8_byte_t) (digit + '0'); if (i == 1 && i != precision) { *actual_char_p++ = '.'; } } *actual_char_p++ = 'e'; exponent--; if (exponent < 0) { exponent *= -1; *actual_char_p++ = '-'; } else { *actual_char_p++ = '+'; } /* Get magnitude of exponent. */ int32_t scale_expt = 1; while (scale_expt <= exponent) { scale_expt *= 10; } scale_expt /= 10; /* Add exponent digits. */ if (exponent == 0) { *actual_char_p++ = '0'; } else { while (scale_expt > 0) { digit = exponent / scale_expt; exponent %= scale_expt; *actual_char_p++ = (lit_utf8_byte_t) (digit + '0'); scale_expt /= 10; } } } /* Fixed notation. */ else { /* Add leading zeros if neccessary. */ if (exponent <= 0) { *actual_char_p++ = '0'; *actual_char_p++ = '.'; for (int i = exponent; i < 0; i++) { *actual_char_p++ = '0'; } } /* Add significant digits. */ for (int i = 1; i <= precision; i++) { digit = 0; scale /= 10; while (digits >= scale && scale > 0) { digits -= scale; digit++; } *actual_char_p++ = (lit_utf8_byte_t) (digit + '0'); if (i == exponent && i != precision) { *actual_char_p++ = '.'; } } } JERRY_ASSERT (actual_char_p - buff < buffer_size); *actual_char_p = '\0'; ecma_string_t *str_p = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) (actual_char_p - buff)); ret_value = ecma_make_string_value (str_p); MEM_FINALIZE_LOCAL_ARRAY (buff); } } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); } ECMA_FINALIZE (this_value); return ret_value; } /* ecma_builtin_number_prototype_object_to_precision */
/** * The Object object's 'defineProperties' routine * * See also: * ECMA-262 v5, 15.2.3.7 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_define_properties (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg1, /**< routine's first argument */ ecma_value_t arg2) /**< routine's second argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 1. if (!ecma_is_value_object (arg1)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg1); // 2. ECMA_TRY_CATCH (props, ecma_op_to_object (arg2), ret_value); ecma_object_t *props_p = ecma_get_object_from_value (props); // 3. ecma_collection_header_t *prop_names_p = ecma_op_object_get_property_names (props_p, false, true, false); uint32_t property_number = prop_names_p->unit_number; ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, prop_names_p); // 4. MEM_DEFINE_LOCAL_ARRAY (property_descriptors, property_number, ecma_property_descriptor_t); uint32_t property_descriptor_number = 0; while (ecma_collection_iterator_next (&iter) && ecma_is_completion_value_empty (ret_value)) { // 5.a ECMA_TRY_CATCH (desc_obj, ecma_op_object_get (props_p, ecma_get_string_from_value (*iter.current_value_p)), ret_value); // 5.b ECMA_TRY_CATCH (conv_result, ecma_op_to_property_descriptor (desc_obj, &property_descriptors[property_descriptor_number]), ret_value); property_descriptor_number++; ECMA_FINALIZE (conv_result); ECMA_FINALIZE (desc_obj); } // 6. ecma_collection_iterator_init (&iter, prop_names_p); for (uint32_t index = 0; index < property_number && ecma_is_completion_value_empty (ret_value); index++) { bool is_next = ecma_collection_iterator_next (&iter); JERRY_ASSERT (is_next); ECMA_TRY_CATCH (define_own_prop_ret, ecma_op_object_define_own_property (obj_p, ecma_get_string_from_value (*iter.current_value_p), &property_descriptors[index], true), ret_value); ECMA_FINALIZE (define_own_prop_ret); } // Clean up for (uint32_t index = 0; index < property_descriptor_number; index++) { ecma_free_property_descriptor (&property_descriptors[index]); } MEM_FINALIZE_LOCAL_ARRAY (property_descriptors); ecma_free_values_collection (prop_names_p, true); // 7. if (ecma_is_completion_value_empty (ret_value)) { ret_value = ecma_make_normal_completion_value (ecma_copy_value (arg1, true)); } ECMA_FINALIZE (props); } return ret_value; } /* ecma_builtin_object_object_define_properties */
/** * Handle calling [[Construct]] of built-in object * * @return completion-value */ ecma_completion_value_t ecma_builtin_dispatch_construct (ecma_object_t *obj_p, /**< built-in object */ ecma_collection_header_t* arg_collection_p) /**< arguments collection */ { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION); JERRY_ASSERT (ecma_get_object_is_builtin (obj_p)); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); const ecma_length_t arguments_list_len = arg_collection_p != NULL ? arg_collection_p->unit_number : 0; MEM_DEFINE_LOCAL_ARRAY (arguments_list_p, arguments_list_len, ecma_value_t); ecma_collection_iterator_t arg_collection_iter; ecma_collection_iterator_init (&arg_collection_iter, arg_collection_p); for (ecma_length_t arg_index = 0; ecma_collection_iterator_next (&arg_collection_iter); arg_index++) { arguments_list_p[arg_index] = *arg_collection_iter.current_value_p; } ecma_property_t *built_in_id_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_BUILT_IN_ID); ecma_builtin_id_t builtin_id = (ecma_builtin_id_t) built_in_id_prop_p->u.internal_property.value; JERRY_ASSERT (ecma_builtin_is (obj_p, builtin_id)); JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION); switch (builtin_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_construct (arguments_list_p, \ arguments_list_len); \ } \ break; \ } #include "ecma-builtins.inc.h" case ECMA_BUILTIN_ID__COUNT: { JERRY_UNREACHABLE (); } default: { #ifdef CONFIG_ECMA_COMPACT_PROFILE JERRY_UNREACHABLE (); #else /* CONFIG_ECMA_COMPACT_PROFILE */ JERRY_UNIMPLEMENTED ("The built-in is not implemented."); #endif /* !CONFIG_ECMA_COMPACT_PROFILE */ } } MEM_FINALIZE_LOCAL_ARRAY (arguments_list_p); JERRY_ASSERT (!ecma_is_completion_value_empty (ret_value)); return ret_value; } /* ecma_builtin_dispatch_construct */
/** * Recursive function for RegExp matching. Tests for a regular expression * match and returns a MatchResult value. * * See also: * ECMA-262 v5, 15.10.2.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ static ecma_completion_value_t re_match_regexp (re_matcher_ctx_t *re_ctx_p, /**< RegExp matcher context */ re_bytecode_t *bc_p, /**< pointer to the current RegExp bytecode */ lit_utf8_iterator_t iter, /**< input string iterator */ lit_utf8_iterator_t *out_iter_p) /**< Output: matching substring iterator */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); re_opcode_t op; while ((op = re_get_opcode (&bc_p))) { switch (op) { case RE_OP_MATCH: { JERRY_DDLOG ("Execute RE_OP_MATCH: match\n"); *out_iter_p = iter; ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); return ret_value; /* match */ } case RE_OP_CHAR: { if (lit_utf8_iterator_is_eos (&iter)) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } bool is_ignorecase = re_ctx_p->flags & RE_FLAG_IGNORE_CASE; ecma_char_t ch1 = (ecma_char_t) re_get_value (&bc_p); /* Already canonicalized. */ ecma_char_t ch2 = re_canonicalize (lit_utf8_iterator_read_next (&iter), is_ignorecase); JERRY_DDLOG ("Character matching %d to %d: ", ch1, ch2); if (ch1 != ch2) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_PERIOD: { if (lit_utf8_iterator_is_eos (&iter)) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } ecma_char_t ch = lit_utf8_iterator_read_next (&iter); JERRY_DDLOG ("Period matching '.' to %d: ", (uint32_t) ch); if (lit_char_is_line_terminator (ch)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_ASSERT_START: { JERRY_DDLOG ("Execute RE_OP_ASSERT_START: "); if ((iter.buf_p + iter.buf_pos.offset) <= re_ctx_p->input_start_p) { JERRY_DDLOG ("match\n"); break; } if (!(re_ctx_p->flags & RE_FLAG_MULTILINE)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } if (lit_char_is_line_terminator (lit_utf8_iterator_peek_prev (&iter))) { JERRY_DDLOG ("match\n"); break; } JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_ASSERT_END: { JERRY_DDLOG ("Execute RE_OP_ASSERT_END: "); if ((iter.buf_p + iter.buf_pos.offset) >= re_ctx_p->input_end_p) { JERRY_DDLOG ("match\n"); break; /* tail merge */ } if (!(re_ctx_p->flags & RE_FLAG_MULTILINE)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } if (lit_char_is_line_terminator (lit_utf8_iterator_peek_next (&iter))) { JERRY_DDLOG ("match\n"); break; /* tail merge */ } JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_ASSERT_WORD_BOUNDARY: case RE_OP_ASSERT_NOT_WORD_BOUNDARY: { bool is_wordchar_left, is_wordchar_right; if ((iter.buf_p + iter.buf_pos.offset) <= re_ctx_p->input_start_p) { is_wordchar_left = false; /* not a wordchar */ } else { is_wordchar_left = lit_char_is_word_char (lit_utf8_iterator_peek_prev (&iter)); } if ((iter.buf_p + iter.buf_pos.offset) >= re_ctx_p->input_end_p) { is_wordchar_right = false; /* not a wordchar */ } else { is_wordchar_right = lit_char_is_word_char (lit_utf8_iterator_peek_next (&iter)); } if (op == RE_OP_ASSERT_WORD_BOUNDARY) { JERRY_DDLOG ("Execute RE_OP_ASSERT_WORD_BOUNDARY: "); if (is_wordchar_left == is_wordchar_right) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } else { JERRY_ASSERT (op == RE_OP_ASSERT_NOT_WORD_BOUNDARY); JERRY_DDLOG ("Execute RE_OP_ASSERT_NOT_WORD_BOUNDARY: "); if (is_wordchar_left != is_wordchar_right) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_LOOKAHEAD_POS: case RE_OP_LOOKAHEAD_NEG: { ecma_completion_value_t match_value = ecma_make_empty_completion_value (); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); uint32_t array_size = re_ctx_p->num_of_captures + re_ctx_p->num_of_non_captures; MEM_DEFINE_LOCAL_ARRAY (saved_bck_p, array_size, lit_utf8_iterator_t); size_t size = (size_t) (array_size) * sizeof (lit_utf8_iterator_t); memcpy (saved_bck_p, re_ctx_p->saved_p, size); do { uint32_t offset = re_get_value (&bc_p); if (!sub_iter.buf_p) { match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_completion_value_throw (match_value)) { break; } } bc_p += offset; } while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); if (!ecma_is_completion_value_throw (match_value)) { JERRY_DDLOG ("Execute RE_OP_LOOKAHEAD_POS/NEG: "); ecma_free_completion_value (match_value); if ((op == RE_OP_LOOKAHEAD_POS && sub_iter.buf_p) || (op == RE_OP_LOOKAHEAD_NEG && !sub_iter.buf_p)) { JERRY_DDLOG ("match\n"); match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); } else { JERRY_DDLOG ("fail\n"); match_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } if (!ecma_is_completion_value_throw (match_value)) { if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; } else { JERRY_ASSERT (ecma_is_value_boolean (match_value)); /* restore saved */ memcpy (re_ctx_p->saved_p, saved_bck_p, size); } } MEM_FINALIZE_LOCAL_ARRAY (saved_bck_p); return match_value; } case RE_OP_CHAR_CLASS: case RE_OP_INV_CHAR_CLASS: { uint32_t num_of_ranges; bool is_match; JERRY_DDLOG ("Execute RE_OP_CHAR_CLASS/RE_OP_INV_CHAR_CLASS, "); if (lit_utf8_iterator_is_eos (&iter)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } bool is_ignorecase = re_ctx_p->flags & RE_FLAG_IGNORE_CASE; ecma_char_t curr_ch = re_canonicalize (lit_utf8_iterator_read_next (&iter), is_ignorecase); num_of_ranges = re_get_value (&bc_p); is_match = false; while (num_of_ranges) { ecma_char_t ch1 = re_canonicalize ((ecma_char_t) re_get_value (&bc_p), is_ignorecase); ecma_char_t ch2 = re_canonicalize ((ecma_char_t) re_get_value (&bc_p), is_ignorecase); JERRY_DDLOG ("num_of_ranges=%d, ch1=%d, ch2=%d, curr_ch=%d; ", num_of_ranges, ch1, ch2, curr_ch); if (curr_ch >= ch1 && curr_ch <= ch2) { /* We must read all the ranges from bytecode. */ is_match = true; } num_of_ranges--; } if (op == RE_OP_CHAR_CLASS) { if (!is_match) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } else { JERRY_ASSERT (op == RE_OP_INV_CHAR_CLASS); if (is_match) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_BACKREFERENCE: { uint32_t backref_idx; backref_idx = re_get_value (&bc_p); JERRY_DDLOG ("Execute RE_OP_BACKREFERENCE (idx: %d): ", backref_idx); backref_idx *= 2; /* backref n -> saved indices [n*2, n*2+1] */ JERRY_ASSERT (backref_idx >= 2 && backref_idx + 1 < re_ctx_p->num_of_captures); if (!re_ctx_p->saved_p[backref_idx].buf_p || !re_ctx_p->saved_p[backref_idx + 1].buf_p) { JERRY_DDLOG ("match\n"); break; /* capture is 'undefined', always matches! */ } lit_utf8_iterator_t sub_iter = re_ctx_p->saved_p[backref_idx]; while (sub_iter.buf_pos.offset < re_ctx_p->saved_p[backref_idx + 1].buf_pos.offset) { ecma_char_t ch1, ch2; if ((iter.buf_p + iter.buf_pos.offset) >= re_ctx_p->input_end_p) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } ch1 = lit_utf8_iterator_read_next (&sub_iter); ch2 = lit_utf8_iterator_read_next (&iter); if (ch1 != ch2) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_SAVE_AT_START: { re_bytecode_t *old_bc_p; JERRY_DDLOG ("Execute RE_OP_SAVE_AT_START\n"); lit_utf8_iterator_t old_start_p = re_ctx_p->saved_p[RE_GLOBAL_START_IDX]; re_ctx_p->saved_p[RE_GLOBAL_START_IDX] = iter; do { uint32_t offset = re_get_value (&bc_p); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } bc_p += offset; old_bc_p = bc_p; } while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); bc_p = old_bc_p; re_ctx_p->saved_p[RE_GLOBAL_START_IDX] = old_start_p; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_SAVE_AND_MATCH: { JERRY_DDLOG ("End of pattern is reached: match\n"); re_ctx_p->saved_p[RE_GLOBAL_END_IDX] = iter; *out_iter_p = iter; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); /* match */ } case RE_OP_ALTERNATIVE: { /* * Alternatives should be jump over, when alternative opcode appears. */ uint32_t offset = re_get_value (&bc_p); JERRY_DDLOG ("Execute RE_OP_ALTERNATIVE"); bc_p += offset; while (*bc_p == RE_OP_ALTERNATIVE) { JERRY_DDLOG (", jump: %d"); bc_p++; offset = re_get_value (&bc_p); bc_p += offset; } JERRY_DDLOG ("\n"); break; /* tail merge */ } case RE_OP_CAPTURE_NON_GREEDY_ZERO_GROUP_START: case RE_OP_NON_CAPTURE_NON_GREEDY_ZERO_GROUP_START: { /* * On non-greedy iterations we have to execute the bytecode * after the group first, if zero iteration is allowed. */ uint32_t start_idx, iter_idx, offset; lit_utf8_iterator_t old_start = lit_utf8_iterator_create (NULL, 0); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); re_bytecode_t *old_bc_p; old_bc_p = bc_p; /* save the bytecode start position of the group start */ start_idx = re_get_value (&bc_p); offset = re_get_value (&bc_p); if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (start_idx <= re_ctx_p->num_of_captures / 2); iter_idx = start_idx - 1; start_idx *= 2; old_start = re_ctx_p->saved_p[start_idx]; re_ctx_p->saved_p[start_idx] = iter; } else { JERRY_ASSERT (start_idx < re_ctx_p->num_of_non_captures); iter_idx = start_idx + (re_ctx_p->num_of_captures / 2) - 1; start_idx += re_ctx_p->num_of_captures; } re_ctx_p->num_of_iterations_p[iter_idx] = 0; /* Jump all over to the end of the END opcode. */ bc_p += offset; /* Try to match after the close paren if zero is allowed */ ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } if (RE_IS_CAPTURE_GROUP (op)) { re_ctx_p->saved_p[start_idx] = old_start; } bc_p = old_bc_p; /* FALLTHRU */ } case RE_OP_CAPTURE_GROUP_START: case RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START: case RE_OP_NON_CAPTURE_GROUP_START: case RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START: { uint32_t start_idx, iter_idx, old_iteration_cnt, offset; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); re_bytecode_t *old_bc_p; re_bytecode_t *end_bc_p = NULL; start_idx = re_get_value (&bc_p); if (op != RE_OP_CAPTURE_GROUP_START && op != RE_OP_NON_CAPTURE_GROUP_START) { offset = re_get_value (&bc_p); end_bc_p = bc_p + offset; } if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (start_idx <= re_ctx_p->num_of_captures / 2); iter_idx = start_idx - 1; start_idx *= 2; } else { JERRY_ASSERT (start_idx < re_ctx_p->num_of_non_captures); iter_idx = start_idx + (re_ctx_p->num_of_captures / 2) - 1; start_idx += re_ctx_p->num_of_captures; } lit_utf8_iterator_t old_start = re_ctx_p->saved_p[start_idx]; old_iteration_cnt = re_ctx_p->num_of_iterations_p[iter_idx]; re_ctx_p->saved_p[start_idx] = iter; re_ctx_p->num_of_iterations_p[iter_idx] = 0; do { offset = re_get_value (&bc_p); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } bc_p += offset; old_bc_p = bc_p; } while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); bc_p = old_bc_p; re_ctx_p->num_of_iterations_p[iter_idx] = old_iteration_cnt; /* Try to match after the close paren if zero is allowed. */ if (op == RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START || op == RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START) { JERRY_ASSERT (end_bc_p); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, end_bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } } re_ctx_p->saved_p[start_idx] = old_start; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_CAPTURE_NON_GREEDY_GROUP_END: case RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END: { uint32_t end_idx, iter_idx, min, max; re_bytecode_t *old_bc_p; /* * On non-greedy iterations we have to execute the bytecode * after the group first. Try to iterate only if it fails. */ old_bc_p = bc_p; /* save the bytecode start position of the group end */ end_idx = re_get_value (&bc_p); min = re_get_value (&bc_p); max = re_get_value (&bc_p); re_get_value (&bc_p); /* start offset */ if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_captures / 2); iter_idx = end_idx - 1; end_idx = (end_idx * 2) + 1; } else { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_non_captures); iter_idx = end_idx + (re_ctx_p->num_of_captures / 2) - 1; end_idx += re_ctx_p->num_of_captures; } re_ctx_p->num_of_iterations_p[iter_idx]++; if (re_ctx_p->num_of_iterations_p[iter_idx] >= min && re_ctx_p->num_of_iterations_p[iter_idx] <= max) { lit_utf8_iterator_t old_end = re_ctx_p->saved_p[end_idx]; re_ctx_p->saved_p[end_idx] = iter; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } re_ctx_p->saved_p[end_idx] = old_end; } re_ctx_p->num_of_iterations_p[iter_idx]--; bc_p = old_bc_p; /* If non-greedy fails and try to iterate... */ /* FALLTHRU */ } case RE_OP_CAPTURE_GREEDY_GROUP_END: case RE_OP_NON_CAPTURE_GREEDY_GROUP_END: { uint32_t start_idx, end_idx, iter_idx, min, max, offset; lit_utf8_iterator_t old_start = lit_utf8_iterator_create (NULL, 0); lit_utf8_iterator_t old_end = lit_utf8_iterator_create (NULL, 0); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); re_bytecode_t *old_bc_p; end_idx = re_get_value (&bc_p); min = re_get_value (&bc_p); max = re_get_value (&bc_p); offset = re_get_value (&bc_p); if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_captures / 2); iter_idx = end_idx - 1; start_idx = end_idx * 2; end_idx = start_idx + 1; } else { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_non_captures); iter_idx = end_idx + (re_ctx_p->num_of_captures / 2) - 1; end_idx += re_ctx_p->num_of_captures; start_idx = end_idx; } /* Check the empty iteration if the minimum number of iterations is reached. */ if (re_ctx_p->num_of_iterations_p[iter_idx] >= min && iter.buf_p == re_ctx_p->saved_p[start_idx].buf_p && iter.buf_pos.offset == re_ctx_p->saved_p[start_idx].buf_pos.offset) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } re_ctx_p->num_of_iterations_p[iter_idx]++; old_bc_p = bc_p; /* Save the bytecode end position of the END opcodes for matching after it. */ old_end = re_ctx_p->saved_p[end_idx]; re_ctx_p->saved_p[end_idx] = iter; if (re_ctx_p->num_of_iterations_p[iter_idx] < max) { bc_p -= offset; offset = re_get_value (&bc_p); old_start = re_ctx_p->saved_p[start_idx]; re_ctx_p->saved_p[start_idx] = iter; ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } re_ctx_p->saved_p[start_idx] = old_start; /* Try to match alternatives if any. */ bc_p += offset; while (*bc_p == RE_OP_ALTERNATIVE) { bc_p++; /* RE_OP_ALTERNATIVE */ offset = re_get_value (&bc_p); old_start = re_ctx_p->saved_p[start_idx]; re_ctx_p->saved_p[start_idx] = iter; ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } re_ctx_p->saved_p[start_idx] = old_start; bc_p += offset; } } if (re_ctx_p->num_of_iterations_p[iter_idx] >= min && re_ctx_p->num_of_iterations_p[iter_idx] <= max) { /* Try to match the rest of the bytecode. */ ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, old_bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } } /* restore if fails */ re_ctx_p->saved_p[end_idx] = old_end; re_ctx_p->num_of_iterations_p[iter_idx]--; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_NON_GREEDY_ITERATOR: { uint32_t min, max, offset, num_of_iter; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); min = re_get_value (&bc_p); max = re_get_value (&bc_p); offset = re_get_value (&bc_p); JERRY_DDLOG ("Non-greedy iterator, min=%lu, max=%lu, offset=%ld\n", (unsigned long) min, (unsigned long) max, (long) offset); num_of_iter = 0; while (num_of_iter <= max) { if (num_of_iter >= min) { ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p + offset, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } } ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (!ecma_is_value_true (match_value)) { if (ecma_is_completion_value_throw (match_value)) { return match_value; } break; } iter = sub_iter; num_of_iter++; } return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_GREEDY_ITERATOR: { uint32_t min, max, offset, num_of_iter; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); min = re_get_value (&bc_p); max = re_get_value (&bc_p); offset = re_get_value (&bc_p); JERRY_DDLOG ("Greedy iterator, min=%lu, max=%lu, offset=%ld\n", (unsigned long) min, (unsigned long) max, (long) offset); num_of_iter = 0; while (num_of_iter < max) { ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (!ecma_is_value_true (match_value)) { if (ecma_is_completion_value_throw (match_value)) { return match_value; } break; } iter = sub_iter; num_of_iter++; } while (num_of_iter >= min) { ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p + offset, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } if (num_of_iter == min) { break; } lit_utf8_iterator_read_prev (&iter); num_of_iter--; } return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } default: { JERRY_DDLOG ("UNKNOWN opcode (%d)!\n", (uint32_t) op); return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_COMMON)); } } } JERRY_UNREACHABLE (); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } /* regexp_match */
/* * Helper function for string indexOf and lastIndexOf functions * * This function implements string indexOf and lastIndexOf with required checks and conversions. * * See also: * ECMA-262 v5, 15.5.4.7 * ECMA-262 v5, 15.5.4.8 * * Used by: * - The String.prototype.indexOf routine. * - The String.prototype.lastIndexOf routine. * * @return uint32_t - (last)index of search string */ ecma_completion_value_t ecma_builtin_helper_string_prototype_object_index_of (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg1, /**< routine's first argument */ ecma_value_t arg2, /**< routine's second argument */ bool firstIndex) /**< routine's third argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 1 */ ECMA_TRY_CATCH (check_coercible_val, ecma_op_check_object_coercible (this_arg), ret_value); /* 2 */ ECMA_TRY_CATCH (to_str_val, ecma_op_to_string (this_arg), ret_value); /* 3 */ ECMA_TRY_CATCH (search_str_val, ecma_op_to_string (arg1), ret_value); /* 4 */ ECMA_OP_TO_NUMBER_TRY_CATCH (pos_num, arg2, ret_value); /* 6 */ ecma_string_t *original_str_p = ecma_get_string_from_value (to_str_val); const ecma_length_t original_len = ecma_string_get_length (original_str_p); const lit_utf8_size_t original_size = ecma_string_get_size (original_str_p); /* 4b, 5, 7 */ ecma_length_t start = ecma_builtin_helper_string_index_normalize (pos_num, original_len, firstIndex); /* 8 */ ecma_string_t *search_str_p = ecma_get_string_from_value (search_str_val); const ecma_length_t search_len = ecma_string_get_length (search_str_p); const lit_utf8_size_t search_size = ecma_string_get_size (search_str_p); ecma_number_t *ret_num_p = ecma_alloc_number (); *ret_num_p = ecma_int32_to_number (-1); /* 9 */ if (search_len <= original_len) { if (!search_len) { *ret_num_p = ecma_uint32_to_number (firstIndex ? 0 : original_len); } else { /* create utf8 string from original string and advance to position */ MEM_DEFINE_LOCAL_ARRAY (original_str_utf8_p, original_size, lit_utf8_byte_t); ecma_string_to_utf8_string (original_str_p, original_str_utf8_p, (ssize_t) (original_size)); lit_utf8_iterator_t original_it = lit_utf8_iterator_create (original_str_utf8_p, original_size); ecma_length_t index = start; lit_utf8_iterator_advance (&original_it, index); /* create utf8 string from search string */ MEM_DEFINE_LOCAL_ARRAY (search_str_utf8_p, search_size, lit_utf8_byte_t); ecma_string_to_utf8_string (search_str_p, search_str_utf8_p, (ssize_t) (search_size)); lit_utf8_iterator_t search_it = lit_utf8_iterator_create (search_str_utf8_p, search_size); /* iterate original string and try to match at each position */ bool searching = true; while (searching) { /* match as long as possible */ ecma_length_t match_len = 0; lit_utf8_iterator_t stored_original_it = original_it; while (match_len < search_len && index + match_len < original_len && lit_utf8_iterator_read_next (&original_it) == lit_utf8_iterator_read_next (&search_it)) { match_len++; } /* check for match */ if (match_len == search_len) { *ret_num_p = ecma_uint32_to_number (index); break; } else { /* inc/dec index and update iterators and search condition */ lit_utf8_iterator_seek_bos (&search_it); original_it = stored_original_it; if (firstIndex) { if ((searching = (index <= original_len - search_len))) { lit_utf8_iterator_incr (&original_it); index++; } } else { if ((searching = (index > 0))) { lit_utf8_iterator_decr (&original_it); index--; } } } } MEM_FINALIZE_LOCAL_ARRAY (search_str_utf8_p); MEM_FINALIZE_LOCAL_ARRAY (original_str_utf8_p); } } ecma_value_t new_value = ecma_make_number_value (ret_num_p); ret_value = ecma_make_normal_completion_value (new_value); ECMA_OP_TO_NUMBER_FINALIZE (pos_num); ECMA_FINALIZE (search_str_val); ECMA_FINALIZE (to_str_val); ECMA_FINALIZE (check_coercible_val); return ret_value; } /* ecma_builtin_helper_string_index_normalize */
/** * The Number.prototype object's 'toString' routine * * See also: * ECMA-262 v5, 15.7.4.2 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_to_string (ecma_value_t this_arg, /**< this argument */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< number of arguments */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (this_value, ecma_builtin_number_prototype_object_value_of (this_arg), ret_value); ecma_number_t this_arg_number = *ecma_get_number_from_value (this_value); if (arguments_list_len == 0 || ecma_number_is_nan (this_arg_number) || ecma_number_is_infinity (this_arg_number) || ecma_number_is_zero (this_arg_number) || (arguments_list_len > 0 && ecma_is_value_undefined (arguments_list_p[0]))) { ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number); ret_value = ecma_make_string_value (ret_str_p); } else { const lit_utf8_byte_t digit_chars[36] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arguments_list_p[0], ret_value); uint32_t radix = ecma_number_to_uint32 (arg_num); if (radix < 2 || radix > 36) { ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("")); } else if (radix == 10) { ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number); ret_value = ecma_make_string_value (ret_str_p); } else { uint64_t digits; int32_t num_digits; int32_t exponent; bool is_negative = false; bool should_round = false; if (ecma_number_is_negative (this_arg_number)) { this_arg_number = -this_arg_number; is_negative = true; } ecma_number_to_decimal (this_arg_number, &digits, &num_digits, &exponent); exponent = exponent - num_digits; bool is_scale_negative = false; /* Calculate the scale of the number in the specified radix. */ int scale = (int) -floor ((log (10) / log (radix)) * exponent); if (scale < 0) { is_scale_negative = true; scale = -scale; } int buff_size; if (is_scale_negative) { buff_size = (int) floor (log (this_arg_number) / log (radix)) + 1; } else { buff_size = scale + ECMA_NUMBER_FRACTION_WIDTH + 2; } if (is_negative) { buff_size++; } /* Normalize the number, so that it is as close to 0 exponent as possible. */ for (int i = 0; i < scale; i++) { if (is_scale_negative) { this_arg_number /= (ecma_number_t) radix; } else { this_arg_number *= (ecma_number_t) radix; } } uint64_t whole = (uint64_t) this_arg_number; ecma_number_t fraction = this_arg_number - (ecma_number_t) whole; if (!ecma_number_is_zero (fraction) && is_scale_negative) { /* Add one extra digit for rounding. */ buff_size++; should_round = true; } MEM_DEFINE_LOCAL_ARRAY (buff, buff_size, lit_utf8_byte_t); int buff_index = 0; /* Calculate digits for whole part. */ while (whole > 0) { buff[buff_index++] = (lit_utf8_byte_t) (whole % radix); whole /= radix; } /* Calculate where we have to put the radix point. */ int point = is_scale_negative ? buff_index + scale : buff_index - scale; /* Reverse the digits, since they are backwards. */ for (int i = 0; i < buff_index / 2; i++) { lit_utf8_byte_t swap = buff[i]; buff[i] = buff[buff_index - i - 1]; buff[buff_index - i - 1] = swap; } int required_digits = buff_size; if (is_negative) { required_digits--; } if (!is_scale_negative) { /* Leave space for leading zeros / radix point. */ required_digits -= scale + 1; } /* Calculate digits for fractional part. */ while (buff_index < required_digits && (fraction != 0 || is_scale_negative)) { fraction *= (ecma_number_t) radix; lit_utf8_byte_t digit = (lit_utf8_byte_t) floor (fraction); buff[buff_index++] = digit; fraction -= (ecma_number_t) floor (fraction); } if (should_round) { /* Round off last digit. */ if (buff[buff_index - 1] > radix / 2) { buff[buff_index - 2]++; } buff_index--; /* Propagate carry. */ for (int i = buff_index - 1; i > 0 && buff[i] >= radix; i--) { buff[i] = (lit_utf8_byte_t) (buff[i] - radix); buff[i - 1]++; } /* Carry propagated over the whole number, need to add a leading digit. */ if (buff[0] >= radix) { memmove (buff + 1, buff, (size_t) buff_index); buff_index++; buff[0] = 1; } } /* Remove trailing zeros from fraction. */ while (buff_index - 1 > point && buff[buff_index - 1] == 0) { buff_index--; } /* Add leading zeros in case place of radix point is negative. */ if (point <= 0) { memmove (buff - point + 1, buff, (size_t) buff_index); buff_index += -point + 1; for (int i = 0; i < -point + 1; i++) { buff[i] = 0; } point = 1; } /* Convert digits to characters. */ for (int i = 0; i < buff_index; i++) { buff[i] = digit_chars[buff[i]]; } /* Place radix point to the required position. */ if (point < buff_index) { memmove (buff + point + 1, buff + point, (size_t) buff_index); buff[point] = '.'; buff_index++; } /* Add negative sign if necessary. */ if (is_negative) { memmove (buff + 1, buff, (size_t) buff_index); buff_index++; buff[0] = '-'; } JERRY_ASSERT (buff_index <= buff_size); ecma_string_t *str_p = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) buff_index); ret_value = ecma_make_string_value (str_p); MEM_FINALIZE_LOCAL_ARRAY (buff); } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); } ECMA_FINALIZE (this_value); return ret_value; } /* ecma_builtin_number_prototype_object_to_string */
/** * The Function.prototype object's 'apply' routine * * See also: * ECMA-262 v5, 15.3.4.3 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_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_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 1. */ if (!ecma_op_is_callable (this_arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } 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_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg2); ecma_string_t *length_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); /* 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. */ MEM_DEFINE_LOCAL_ARRAY (arg_list, length, ecma_value_t); /* 7. */ uint32_t appended_num = 0; for (uint32_t index = 0; index < length && ecma_is_completion_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); arg_list[index] = ecma_copy_value (get_value, true); appended_num++; ECMA_FINALIZE (get_value); ecma_deref_ecma_string (curr_idx_str_p); } JERRY_ASSERT (appended_num == length || !ecma_is_completion_value_empty (ret_value)); if (ecma_is_completion_value_empty (ret_value)) { ret_value = ecma_op_function_call (func_obj_p, arg1, arg_list, (ecma_length_t) appended_num); } for (uint32_t index = 0; index < appended_num; index++) { ecma_free_value (arg_list[index], true); } MEM_FINALIZE_LOCAL_ARRAY (arg_list); 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 JSON object's 'parse' routine * * See also: * ECMA-262 v5, 15.12.2 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_json_parse (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg1, /**< string argument */ ecma_value_t arg2) /**< reviver argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (string, ecma_op_to_string (arg1), ret_value); ecma_string_t *string_p = ecma_get_string_from_value (string); ecma_length_t string_size = (uint32_t) ecma_string_get_size (string_p); size_t buffer_size = sizeof (lit_utf8_byte_t) * (string_size + 1); MEM_DEFINE_LOCAL_ARRAY (str_start_p, buffer_size, lit_utf8_byte_t); ssize_t sz = ecma_string_to_utf8_string (string_p, str_start_p, (ssize_t) buffer_size); JERRY_ASSERT (sz == (ssize_t) string_size); str_start_p[string_size] = LIT_BYTE_NULL; ecma_json_token_t token; token.current_p = str_start_p; token.end_p = str_start_p + string_size; ecma_value_t final_result = ecma_builtin_json_parse_value (&token); if (!ecma_is_value_undefined (final_result)) { ecma_builtin_json_parse_next_token (&token); if (token.type != end_token) { ecma_free_value (final_result); final_result = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } if (ecma_is_value_undefined (final_result)) { ret_value = ecma_raise_syntax_error (""); } else { if (ecma_op_is_callable (arg2)) { ecma_object_t *object_p = ecma_op_create_object_object_noarg (); ecma_string_t *name_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); ecma_property_t *property_p = ecma_create_named_data_property (object_p, name_p, true, true, true); ecma_named_data_property_assign_value (object_p, property_p, final_result); ecma_free_value (final_result); ret_value = ecma_builtin_json_walk (ecma_get_object_from_value (arg2), object_p, name_p); ecma_deref_object (object_p); ecma_deref_ecma_string (name_p); } else { ret_value = final_result; } } MEM_FINALIZE_LOCAL_ARRAY (str_start_p); ECMA_FINALIZE (string); return ret_value; } /* ecma_builtin_json_parse */
/** * Abstract operation 'Quote' defined in 15.12.3 * * See also: * ECMA-262 v5, 15.12.3 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_json_quote (ecma_string_t *string_p) /**< string that should be quoted*/ { /* 1. */ ecma_string_t *quote_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR); ecma_string_t *product_str_p = ecma_copy_or_ref_ecma_string (quote_str_p); ecma_string_t *tmp_str_p; ecma_length_t string_size = ecma_string_get_size (string_p); MEM_DEFINE_LOCAL_ARRAY (string_buff, string_size, lit_utf8_byte_t); ssize_t bytes_copied = ecma_string_to_utf8_string (string_p, string_buff, (ssize_t) string_size); JERRY_ASSERT (bytes_copied > 0 || !string_size); lit_utf8_byte_t *str_p = string_buff; const lit_utf8_byte_t *str_end_p = str_p + string_size; while (str_p < str_end_p) { ecma_char_t current_char = lit_utf8_read_next (&str_p); /* 2.a */ if (current_char == LIT_CHAR_BACKSLASH || current_char == LIT_CHAR_DOUBLE_QUOTE) { ecma_string_t *backslash_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_BACKSLASH_CHAR); /* 2.a.i */ tmp_str_p = ecma_concat_ecma_strings (product_str_p, backslash_str_p); ecma_deref_ecma_string (product_str_p); ecma_deref_ecma_string (backslash_str_p); product_str_p = tmp_str_p; /* 2.a.ii */ ecma_string_t *current_char_str_p = ecma_new_ecma_string_from_code_unit (current_char); tmp_str_p = ecma_concat_ecma_strings (product_str_p, current_char_str_p); ecma_deref_ecma_string (product_str_p); ecma_deref_ecma_string (current_char_str_p); product_str_p = tmp_str_p; } /* 2.b */ else if (current_char == LIT_CHAR_BS || current_char == LIT_CHAR_FF || current_char == LIT_CHAR_LF || current_char == LIT_CHAR_CR || current_char == LIT_CHAR_TAB) { ecma_string_t *backslash_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_BACKSLASH_CHAR); /* 2.b.i */ tmp_str_p = ecma_concat_ecma_strings (product_str_p, backslash_str_p); ecma_deref_ecma_string (product_str_p); ecma_deref_ecma_string (backslash_str_p); product_str_p = tmp_str_p; /* 2.b.ii */ lit_utf8_byte_t abbrev = LIT_CHAR_SP; switch (current_char) { case LIT_CHAR_BS: { abbrev = LIT_CHAR_LOWERCASE_B; break; } case LIT_CHAR_FF: { abbrev = LIT_CHAR_LOWERCASE_F; break; } case LIT_CHAR_LF: { abbrev = LIT_CHAR_LOWERCASE_N; break; } case LIT_CHAR_CR: { abbrev = LIT_CHAR_LOWERCASE_R; break; } case LIT_CHAR_TAB: { abbrev = LIT_CHAR_LOWERCASE_T; break; } } /* 2.b.iii */ ecma_string_t *abbrev_str_p = ecma_new_ecma_string_from_utf8 (&abbrev, 1); tmp_str_p = ecma_concat_ecma_strings (product_str_p, abbrev_str_p); ecma_deref_ecma_string (product_str_p); ecma_deref_ecma_string (abbrev_str_p); product_str_p = tmp_str_p; } /* 2.c */ else if (current_char < LIT_CHAR_SP) { ecma_string_t *backslash_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_BACKSLASH_CHAR); /* 2.c.i */ tmp_str_p = ecma_concat_ecma_strings (product_str_p, backslash_str_p); ecma_deref_ecma_string (product_str_p); ecma_deref_ecma_string (backslash_str_p); product_str_p = tmp_str_p; /* 2.c.ii */ lit_utf8_byte_t u_ch = LIT_CHAR_LOWERCASE_U; ecma_string_t *u_ch_str_p = ecma_new_ecma_string_from_utf8 (&u_ch, 1); tmp_str_p = ecma_concat_ecma_strings (product_str_p, u_ch_str_p); ecma_deref_ecma_string (product_str_p); ecma_deref_ecma_string (u_ch_str_p); product_str_p = tmp_str_p; /* 2.c.iii */ ecma_string_t *hex_str_p = ecma_builtin_helper_json_create_hex_digit_ecma_string ((uint8_t) current_char); /* 2.c.iv */ tmp_str_p = ecma_concat_ecma_strings (product_str_p, hex_str_p); ecma_deref_ecma_string (product_str_p); ecma_deref_ecma_string (hex_str_p); product_str_p = tmp_str_p; } /* 2.d */ else { ecma_string_t *current_char_str_p = ecma_new_ecma_string_from_code_unit (current_char); tmp_str_p = ecma_concat_ecma_strings (product_str_p, current_char_str_p); ecma_deref_ecma_string (product_str_p); ecma_deref_ecma_string (current_char_str_p); product_str_p = tmp_str_p; } } MEM_FINALIZE_LOCAL_ARRAY (string_buff); /* 3. */ tmp_str_p = ecma_concat_ecma_strings (product_str_p, quote_str_p); ecma_deref_ecma_string (product_str_p); ecma_deref_ecma_string (quote_str_p); product_str_p = tmp_str_p; /* 4. */ return ecma_make_string_value (product_str_p); } /* ecma_builtin_json_quote */
/** * Run the code, starting from specified instruction position */ ecma_completion_value_t vm_run_from_pos (const bytecode_data_header_t *header_p, /**< byte-code data header */ vm_instr_counter_t start_pos, /**< position of starting instruction */ ecma_value_t this_binding_value, /**< value of 'ThisBinding' */ ecma_object_t *lex_env_p, /**< lexical environment to use */ bool is_strict, /**< is the code is strict mode code (ECMA-262 v5, 10.1.1) */ bool is_eval_code, /**< is the code is eval code (ECMA-262 v5, 10.1) */ ecma_collection_header_t *arg_collection_p) /**< * - collection of function call arguments, * if arguments for the called function * are placed on registers; * - NULL - otherwise. */ { ecma_completion_value_t completion; const vm_instr_t *instrs_p = header_p->instrs_p; const vm_instr_t *curr = &instrs_p[start_pos]; JERRY_ASSERT (curr->op_idx == VM_OP_REG_VAR_DECL); const uint32_t tmp_regs_num = curr->data.reg_var_decl.tmp_regs_num; const uint32_t local_var_regs_num = curr->data.reg_var_decl.local_var_regs_num; const uint32_t arg_regs_num = curr->data.reg_var_decl.arg_regs_num; uint32_t regs_num = VM_SPECIAL_REGS_NUMBER + tmp_regs_num + local_var_regs_num + arg_regs_num; MEM_DEFINE_LOCAL_ARRAY (regs, regs_num, ecma_value_t); vm_frame_ctx_t frame_ctx; frame_ctx.bytecode_header_p = header_p; frame_ctx.pos = (vm_instr_counter_t) (start_pos + 1); frame_ctx.lex_env_p = lex_env_p; frame_ctx.is_strict = is_strict; frame_ctx.is_eval_code = is_eval_code; frame_ctx.is_call_in_direct_eval_form = false; frame_ctx.tmp_num_p = ecma_alloc_number (); vm_stack_add_frame (&frame_ctx.stack_frame, regs, regs_num, local_var_regs_num, arg_regs_num, arg_collection_p); vm_stack_frame_set_reg_value (&frame_ctx.stack_frame, VM_REG_SPECIAL_THIS_BINDING, ecma_copy_value (this_binding_value, false)); vm_frame_ctx_t *prev_context_p = vm_top_context_p; vm_top_context_p = &frame_ctx; #ifdef MEM_STATS interp_mem_stats_context_enter (&frame_ctx, start_pos); #endif /* MEM_STATS */ completion = vm_loop (&frame_ctx, NULL); JERRY_ASSERT (ecma_is_completion_value_throw (completion) || ecma_is_completion_value_return (completion)); vm_top_context_p = prev_context_p; vm_stack_free_frame (&frame_ctx.stack_frame); ecma_dealloc_number (frame_ctx.tmp_num_p); #ifdef MEM_STATS interp_mem_stats_context_exit (&frame_ctx, start_pos); #endif /* MEM_STATS */ MEM_FINALIZE_LOCAL_ARRAY (regs); return completion; } /* vm_run_from_pos */
/** * '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 */
/** * RegExp helper function to start the recursive matching algorithm * and create the result Array object * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ ecma_value_t input_string, /**< input string */ bool ignore_global) /**< ignore global flag */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); JERRY_ASSERT (ecma_is_value_object (regexp_value)); JERRY_ASSERT (ecma_is_value_string (input_string)); ecma_object_t *regexp_object_p = ecma_get_object_from_value (regexp_value); JERRY_ASSERT (ecma_object_get_class_name (regexp_object_p) == LIT_MAGIC_STRING_REGEXP_UL); ecma_property_t *bytecode_prop_p = ecma_get_internal_property (regexp_object_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); re_bytecode_t *bc_p = ECMA_GET_POINTER (re_bytecode_t, bytecode_prop_p->u.internal_property.value); ecma_string_t *input_string_p = ecma_get_string_from_value (input_string); lit_utf8_size_t input_string_size = ecma_string_get_size (input_string_p); MEM_DEFINE_LOCAL_ARRAY (input_utf8_buffer_p, input_string_size, lit_utf8_byte_t); ecma_string_to_utf8_string (input_string_p, input_utf8_buffer_p, (ssize_t) input_string_size); lit_utf8_iterator_t iterator = lit_utf8_iterator_create (input_utf8_buffer_p, input_string_size); re_matcher_ctx_t re_ctx; re_ctx.input_start_p = iterator.buf_p; re_ctx.input_end_p = iterator.buf_p + iterator.buf_size; /* 1. Read bytecode header and init regexp matcher context. */ re_ctx.flags = (uint8_t) re_get_value (&bc_p); if (ignore_global) { re_ctx.flags &= (uint8_t) ~RE_FLAG_GLOBAL; } JERRY_DDLOG ("Exec with flags [global: %d, ignoreCase: %d, multiline: %d]\n", re_ctx.flags & RE_FLAG_GLOBAL, re_ctx.flags & RE_FLAG_IGNORE_CASE, re_ctx.flags & RE_FLAG_MULTILINE); re_ctx.num_of_captures = re_get_value (&bc_p); JERRY_ASSERT (re_ctx.num_of_captures % 2 == 0); re_ctx.num_of_non_captures = re_get_value (&bc_p); /* We create an invalid iterator, that will be used to identify unused result values. */ lit_utf8_iterator_t unused_iter = lit_utf8_iterator_create (NULL, 0); unused_iter.buf_p = (lit_utf8_byte_t *) 1; MEM_DEFINE_LOCAL_ARRAY (saved_p, re_ctx.num_of_captures + re_ctx.num_of_non_captures, lit_utf8_iterator_t); for (uint32_t i = 0; i < re_ctx.num_of_captures + re_ctx.num_of_non_captures; i++) { saved_p[i] = unused_iter; } re_ctx.saved_p = saved_p; uint32_t num_of_iter_length = (re_ctx.num_of_captures / 2) + (re_ctx.num_of_non_captures - 1); MEM_DEFINE_LOCAL_ARRAY (num_of_iter_p, num_of_iter_length, uint32_t); for (uint32_t i = 0; i < num_of_iter_length; i++) { num_of_iter_p[i] = 0u; } bool is_match = false; re_ctx.num_of_iterations_p = num_of_iter_p; int32_t index = 0; ecma_length_t input_str_len = lit_utf8_string_length (iterator.buf_p, iterator.buf_size); if (iterator.buf_p && (re_ctx.flags & RE_FLAG_GLOBAL)) { ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_property_t *lastindex_prop_p = ecma_op_object_get_property (regexp_object_p, magic_str_p); ECMA_OP_TO_NUMBER_TRY_CATCH (lastindex_num, lastindex_prop_p->u.named_data_property.value, ret_value) index = ecma_number_to_int32 (lastindex_num); JERRY_ASSERT (iterator.buf_pos.offset == 0 && !iterator.buf_pos.is_non_bmp_middle); if (!lit_utf8_iterator_is_eos (&iterator) && index <= (int32_t) input_str_len && index > 0) { lit_utf8_iterator_advance (&iterator, (ecma_length_t) index); } ECMA_OP_TO_NUMBER_FINALIZE (lastindex_num); ecma_deref_ecma_string (magic_str_p); } /* 2. Try to match */ lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); while (ecma_is_completion_value_empty (ret_value)) { if (index < 0 || index > (int32_t) input_str_len) { if (re_ctx.flags & RE_FLAG_GLOBAL) { ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_number_t *lastindex_num_p = ecma_alloc_number (); *lastindex_num_p = ECMA_NUMBER_ZERO; ecma_op_object_put (regexp_object_p, magic_str_p, ecma_make_number_value (lastindex_num_p), true); ecma_dealloc_number (lastindex_num_p); ecma_deref_ecma_string (magic_str_p); } is_match = false; break; } else { ECMA_TRY_CATCH (match_value, re_match_regexp (&re_ctx, bc_p, iterator, &sub_iter), ret_value); if (ecma_is_value_true (match_value)) { is_match = true; break; } if (!lit_utf8_iterator_is_eos (&iterator)) { lit_utf8_iterator_advance (&iterator, 1); } index++; ECMA_FINALIZE (match_value); } } if (iterator.buf_p && (re_ctx.flags & RE_FLAG_GLOBAL)) { ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_number_t *lastindex_num_p = ecma_alloc_number (); *lastindex_num_p = sub_iter.buf_pos.offset; ecma_op_object_put (regexp_object_p, magic_str_p, ecma_make_number_value (lastindex_num_p), true); ecma_dealloc_number (lastindex_num_p); ecma_deref_ecma_string (magic_str_p); } /* 3. Fill the result array or return with 'undefiend' */ if (ecma_is_completion_value_empty (ret_value)) { if (is_match) { ecma_completion_value_t result_array = ecma_op_create_array_object (0, 0, false); ecma_object_t *result_array_obj_p = ecma_get_object_from_completion_value (result_array); ecma_string_t *input_str_p = ecma_new_ecma_string_from_utf8 (iterator.buf_p, iterator.buf_size); re_set_result_array_properties (result_array_obj_p, input_str_p, re_ctx.num_of_captures / 2, index); ecma_deref_ecma_string (input_str_p); for (uint32_t i = 0; i < re_ctx.num_of_captures; i += 2) { ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (i / 2); /* Note: 'iter_p->buf_p == NULL' means the input is empty string */ if ((re_ctx.saved_p[i].buf_p != unused_iter.buf_p && re_ctx.saved_p[i + 1].buf_p != unused_iter.buf_p) && re_ctx.saved_p[i + 1].buf_pos.offset >= re_ctx.saved_p[i].buf_pos.offset) { ecma_length_t capture_str_len; capture_str_len = (ecma_length_t) re_ctx.saved_p[i + 1].buf_pos.offset - re_ctx.saved_p[i].buf_pos.offset; ecma_string_t *capture_str_p; if (capture_str_len > 0) { const lit_utf8_byte_t *utf8_str_p = re_ctx.saved_p[i].buf_p + re_ctx.saved_p[i].buf_pos.offset; capture_str_p = ecma_new_ecma_string_from_utf8 (utf8_str_p, capture_str_len); } else { capture_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); } ecma_op_object_put (result_array_obj_p, index_str_p, ecma_make_string_value (capture_str_p), true); ecma_deref_ecma_string (capture_str_p); } else { ecma_op_object_put (result_array_obj_p, index_str_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), true); } ecma_deref_ecma_string (index_str_p); } ret_value = result_array; } else { ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL)); } } MEM_FINALIZE_LOCAL_ARRAY (num_of_iter_p); MEM_FINALIZE_LOCAL_ARRAY (saved_p); MEM_FINALIZE_LOCAL_ARRAY (input_utf8_buffer_p); return ret_value; } /* ecma_regexp_exec_helper */
/** * The Number.prototype object's 'toFixed' routine * * See also: * ECMA-262 v5, 15.7.4.5 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_to_fixed (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (this_value, ecma_builtin_number_prototype_object_value_of (this_arg), ret_value); ecma_number_t this_num = *ecma_get_number_from_value (this_value); ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value); /* 2. */ if (arg_num <= -1 || arg_num >= 21) { ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("")); } else { /* 4. */ if (ecma_number_is_nan (this_num)) { ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); ret_value = ecma_make_string_value (nan_str_p); } else { bool is_negative = false; /* 6. */ if (ecma_number_is_negative (this_num)) { is_negative = true; this_num *= -1; } /* We handle infinities separately. */ if (ecma_number_is_infinity (this_num)) { ecma_string_t *infinity_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INFINITY_UL); if (is_negative) { ecma_string_t *neg_str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) "-", 1); ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p); ecma_deref_ecma_string (infinity_str_p); ecma_deref_ecma_string (neg_str_p); ret_value = ecma_make_string_value (neg_inf_str_p); } else { ret_value = ecma_make_string_value (infinity_str_p); } } else { uint64_t digits = 0; int32_t num_digits = 0; int32_t exponent = 1; /* 1. */ int32_t frac_digits = ecma_number_to_int32 (arg_num); /* Get the parameters of the number if non-zero. */ if (!ecma_number_is_zero (this_num)) { ecma_number_to_decimal (this_num, &digits, &num_digits, &exponent); } digits = ecma_builtin_number_prototype_helper_round (digits, num_digits - exponent - frac_digits); /* 7. */ if (exponent > 21) { ret_value = ecma_builtin_number_prototype_object_to_string (this_arg, NULL, 0); } /* 8. */ else { /* Buffer that is used to construct the string. */ int buffer_size = (exponent > 0) ? exponent + frac_digits + 2 : frac_digits + 3; if (is_negative) { buffer_size++; } JERRY_ASSERT (buffer_size > 0); MEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, lit_utf8_byte_t); lit_utf8_byte_t *p = buff; if (is_negative) { *p++ = '-'; } int8_t digit = 0; uint64_t s = 1; /* Calculate the magnitude of the number. This is used to get the digits from left to right. */ while (s <= digits) { s *= 10; } if (exponent <= 0) { /* Add leading zeros. */ *p++ = '0'; if (frac_digits != 0) { *p++ = '.'; } for (int i = 0; i < -exponent && i < frac_digits; i++) { *p++ = '0'; } /* Add significant digits. */ for (int i = -exponent; i < frac_digits; i++) { digit = 0; s /= 10; while (digits >= s && s > 0) { digits -= s; digit++; } *p = (lit_utf8_byte_t) ((lit_utf8_byte_t) digit + '0'); p++; } } else { /* Add significant digits. */ for (int i = 0; i < exponent; i++) { digit = 0; s /= 10; while (digits >= s && s > 0) { digits -= s; digit++; } *p = (lit_utf8_byte_t) ((lit_utf8_byte_t) digit + '0'); p++; } /* Add the decimal point after whole part. */ if (frac_digits != 0) { *p++ = '.'; } /* Add neccessary fracion digits. */ for (int i = 0; i < frac_digits; i++) { digit = 0; s /= 10; while (digits >= s && s > 0) { digits -= s; digit++; } *p = (lit_utf8_byte_t) ((lit_utf8_byte_t) digit + '0'); p++; } } JERRY_ASSERT (p - buff < buffer_size); /* String terminator. */ *p = 0; ecma_string_t *str = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) (p - buff)); ret_value = ecma_make_string_value (str); MEM_FINALIZE_LOCAL_ARRAY (buff); } } } } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); ECMA_FINALIZE (this_value); return ret_value; } /* ecma_builtin_number_prototype_object_to_fixed */
/** * The String.prototype object's 'indexOf' routine * * See also: * ECMA-262 v5, 15.5.4.7 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_string_prototype_object_index_of (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg1, /**< routine's first argument */ ecma_value_t arg2) /**< routine's second argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 1 */ ECMA_TRY_CATCH (check_coercible_val, ecma_op_check_object_coercible (this_arg), ret_value); /* 2 */ ECMA_TRY_CATCH (to_str_val, ecma_op_to_string (this_arg), ret_value); /* 3 */ ECMA_TRY_CATCH (search_str_val, ecma_op_to_string (arg1), ret_value); /* 4 */ ECMA_OP_TO_NUMBER_TRY_CATCH (pos_num, arg2, ret_value); /* 5 */ ecma_string_t *original_str_p = ecma_get_string_from_value (to_str_val); const ecma_length_t original_len = ecma_string_get_length (original_str_p); const lit_utf8_size_t original_size = ecma_string_get_size (original_str_p); /* 4b, 6 */ ecma_length_t start = ecma_builtin_helper_string_index_normalize (pos_num, original_len); /* 7 */ ecma_string_t *search_str_p = ecma_get_string_from_value (search_str_val); const ecma_length_t search_len = ecma_string_get_length (search_str_p); const lit_utf8_size_t search_size = ecma_string_get_size (search_str_p); ecma_number_t *ret_num_p = ecma_alloc_number (); *ret_num_p = ecma_int32_to_number (-1); /* 8 */ if (search_len <= original_len) { if (!search_len) { *ret_num_p = ecma_uint32_to_number (0); } else { /* create utf8 string from original string and advance to start position */ MEM_DEFINE_LOCAL_ARRAY (original_str_utf8_p, original_size, lit_utf8_byte_t); ecma_string_to_utf8_string (original_str_p, original_str_utf8_p, (ssize_t) (original_size)); lit_utf8_iterator_t original_it = lit_utf8_iterator_create (original_str_utf8_p, original_size); ecma_length_t index = start; lit_utf8_iterator_advance (&original_it, index); /* create utf8 string from search string */ MEM_DEFINE_LOCAL_ARRAY (search_str_utf8_p, search_size, lit_utf8_byte_t); ecma_string_to_utf8_string (search_str_p, search_str_utf8_p, (ssize_t) (search_size)); lit_utf8_iterator_t search_it = lit_utf8_iterator_create (search_str_utf8_p, search_size); /* iterate original string and try to match at each position */ bool found = false; while (!found && index <= original_len - search_len) { ecma_length_t match_len = 0; lit_utf8_iterator_pos_t stored_original_pos = lit_utf8_iterator_get_pos (&original_it); while (match_len < search_len && lit_utf8_iterator_read_next (&original_it) == lit_utf8_iterator_read_next (&search_it)) { match_len++; } /* Check for match */ if (match_len == search_len) { *ret_num_p = ecma_uint32_to_number (index); found = true; } else { /* reset iterators */ lit_utf8_iterator_seek_bos (&search_it); lit_utf8_iterator_seek (&original_it, stored_original_pos); lit_utf8_iterator_incr (&original_it); } index++; } MEM_FINALIZE_LOCAL_ARRAY (search_str_utf8_p); MEM_FINALIZE_LOCAL_ARRAY (original_str_utf8_p); } } ecma_value_t new_value = ecma_make_number_value (ret_num_p); ret_value = ecma_make_normal_completion_value (new_value); ECMA_OP_TO_NUMBER_FINALIZE (pos_num); ECMA_FINALIZE (search_str_val); ECMA_FINALIZE (to_str_val); ECMA_FINALIZE (check_coercible_val); return ret_value; } /* ecma_builtin_string_prototype_object_index_of */
/** * Compilation of RegExp bytecode * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t re_compile_bytecode (re_bytecode_t **out_bytecode_p, /**< out:pointer to bytecode */ ecma_string_t *pattern_str_p, /**< pattern */ uint8_t flags) /**< flags */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); re_compiler_ctx_t re_ctx; re_ctx.flags = flags; re_ctx.highest_backref = 0; re_ctx.num_of_non_captures = 0; re_bytecode_ctx_t bc_ctx; bc_ctx.block_start_p = NULL; bc_ctx.block_end_p = NULL; bc_ctx.current_p = NULL; re_ctx.bytecode_ctx_p = &bc_ctx; lit_utf8_size_t pattern_str_size = ecma_string_get_size (pattern_str_p); MEM_DEFINE_LOCAL_ARRAY (pattern_start_p, pattern_str_size, lit_utf8_byte_t); ecma_string_to_utf8_string (pattern_str_p, pattern_start_p, (ssize_t) pattern_str_size); lit_utf8_iterator_t iter = lit_utf8_iterator_create (pattern_start_p, pattern_str_size); re_parser_ctx_t parser_ctx; parser_ctx.iter = iter; parser_ctx.num_of_groups = -1; re_ctx.parser_ctx_p = &parser_ctx; /* 1. Parse RegExp pattern */ re_ctx.num_of_captures = 1; re_append_opcode (&bc_ctx, RE_OP_SAVE_AT_START); ECMA_TRY_CATCH (empty, re_parse_alternative (&re_ctx, true), ret_value); /* 2. Check for invalid backreference */ if (re_ctx.highest_backref >= re_ctx.num_of_captures) { ret_value = ecma_raise_syntax_error ("Invalid backreference.\n"); } else { re_append_opcode (&bc_ctx, RE_OP_SAVE_AND_MATCH); re_append_opcode (&bc_ctx, RE_OP_EOF); /* 3. Insert extra informations for bytecode header */ re_insert_u32 (&bc_ctx, 0, (uint32_t) re_ctx.num_of_non_captures); re_insert_u32 (&bc_ctx, 0, (uint32_t) re_ctx.num_of_captures * 2); re_insert_u32 (&bc_ctx, 0, (uint32_t) re_ctx.flags); } ECMA_FINALIZE (empty); MEM_FINALIZE_LOCAL_ARRAY (pattern_start_p); if (!ecma_is_completion_value_empty (ret_value)) { /* Compilation failed, free bytecode. */ mem_heap_free_block (bc_ctx.block_start_p); *out_bytecode_p = NULL; } else { /* The RegExp bytecode contains at least a RE_OP_SAVE_AT_START opdoce, so it cannot be NULL. */ JERRY_ASSERT (bc_ctx.block_start_p != NULL); *out_bytecode_p = bc_ctx.block_start_p; } #ifdef JERRY_ENABLE_LOG re_dump_bytecode (&bc_ctx); #endif return ret_value; } /* re_compile_bytecode */
ecma_completion_value_t ecma_builtin_helper_object_to_string (const ecma_value_t this_arg) /**< this argument */ { lit_magic_string_id_t type_string; if (ecma_is_value_undefined (this_arg)) { type_string = LIT_MAGIC_STRING_UNDEFINED_UL; } else if (ecma_is_value_null (this_arg)) { type_string = LIT_MAGIC_STRING_NULL_UL; } else { ecma_completion_value_t obj_this = ecma_op_to_object (this_arg); if (!ecma_is_completion_value_normal (obj_this)) { return obj_this; } JERRY_ASSERT (ecma_is_value_object (ecma_get_completion_value_value (obj_this))); ecma_object_t *obj_p = ecma_get_object_from_completion_value (obj_this); type_string = ecma_object_get_class_name (obj_p); ecma_free_completion_value (obj_this); } ecma_string_t *ret_string_p; /* Building string "[object #type#]" where type is 'Undefined', 'Null' or one of possible object's classes. The string with null character is maximum 19 characters long. */ const ssize_t buffer_size = 19; MEM_DEFINE_LOCAL_ARRAY (str_buffer, buffer_size, lit_utf8_byte_t); lit_utf8_byte_t *buffer_ptr = str_buffer; ssize_t buffer_size_left = buffer_size; const lit_magic_string_id_t magic_string_ids[] = { LIT_MAGIC_STRING_LEFT_SQUARE_CHAR, LIT_MAGIC_STRING_OBJECT, LIT_MAGIC_STRING_SPACE_CHAR, type_string, LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR }; for (uint32_t i = 0; i < sizeof (magic_string_ids) / sizeof (lit_magic_string_id_t); ++i) { buffer_ptr = lit_copy_magic_string_to_buffer (magic_string_ids[i], buffer_ptr, buffer_size_left); buffer_size_left = buffer_size - (buffer_ptr - str_buffer); } JERRY_ASSERT (buffer_size_left >= 0); ret_string_p = ecma_new_ecma_string_from_utf8 (str_buffer, (lit_utf8_size_t) (buffer_size - buffer_size_left)); MEM_FINALIZE_LOCAL_ARRAY (str_buffer); return ecma_make_normal_completion_value (ecma_make_string_value (ret_string_p)); } /* ecma_builtin_helper_object_to_string */
/** * Helper function to convert a string to upper or lower case. * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_string_prototype_object_conversion_helper (ecma_value_t this_arg, /**< this argument */ bool lower_case) /**< convert to lower (true) * or upper (false) case */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 1. */ ECMA_TRY_CATCH (check_coercible_val, ecma_op_check_object_coercible (this_arg), ret_value); /* 2. */ ECMA_TRY_CATCH (to_string_val, ecma_op_to_string (this_arg), ret_value); /* 3. */ ecma_string_t *input_string_p = ecma_get_string_from_value (to_string_val); lit_utf8_size_t input_size = ecma_string_get_size (input_string_p); MEM_DEFINE_LOCAL_ARRAY (input_start_p, input_size, lit_utf8_byte_t); ecma_string_to_utf8_string (input_string_p, input_start_p, (ssize_t) (input_size)); /* * The URI encoding has two major phases: first we compute * the length of the lower case string, then we encode it. */ lit_utf8_size_t output_length = 0; lit_utf8_iterator_t input_iterator = lit_utf8_iterator_create (input_start_p, input_size); while (!lit_utf8_iterator_is_eos (&input_iterator)) { ecma_char_t character = lit_utf8_iterator_read_next (&input_iterator); ecma_char_t character_buffer[LIT_MAXIMUM_OTHER_CASE_LENGTH]; lit_utf8_byte_t utf8_byte_buffer[LIT_UTF8_MAX_BYTES_IN_CODE_POINT]; lit_utf8_size_t character_length; /* * We need to keep surrogate pairs. Surrogates are never converted, * regardless they form a valid pair or not. */ if (lit_is_code_unit_high_surrogate (character)) { ecma_char_t next_character = lit_utf8_iterator_peek_next (&input_iterator); if (lit_is_code_unit_low_surrogate (next_character)) { lit_code_point_t surrogate_code_point = lit_convert_surrogate_pair_to_code_point (character, next_character); output_length += lit_code_point_to_utf8 (surrogate_code_point, utf8_byte_buffer); lit_utf8_iterator_incr (&input_iterator); continue; } } if (lower_case) { character_length = lit_char_to_lower_case (character, character_buffer, LIT_MAXIMUM_OTHER_CASE_LENGTH); } else { character_length = lit_char_to_upper_case (character, character_buffer, LIT_MAXIMUM_OTHER_CASE_LENGTH); } JERRY_ASSERT (character_length >= 1 && character_length <= LIT_MAXIMUM_OTHER_CASE_LENGTH); for (lit_utf8_size_t i = 0; i < character_length; i++) { output_length += lit_code_unit_to_utf8 (character_buffer[i], utf8_byte_buffer); } } /* Second phase. */ MEM_DEFINE_LOCAL_ARRAY (output_start_p, output_length, lit_utf8_byte_t); lit_utf8_byte_t *output_char_p = output_start_p; /* Encoding the output. */ lit_utf8_iterator_seek_bos (&input_iterator); while (!lit_utf8_iterator_is_eos (&input_iterator)) { ecma_char_t character = lit_utf8_iterator_read_next (&input_iterator); ecma_char_t character_buffer[LIT_MAXIMUM_OTHER_CASE_LENGTH]; lit_utf8_size_t character_length; /* * We need to keep surrogate pairs. Surrogates are never converted, * regardless they form a valid pair or not. */ if (lit_is_code_unit_high_surrogate (character)) { ecma_char_t next_character = lit_utf8_iterator_peek_next (&input_iterator); if (lit_is_code_unit_low_surrogate (next_character)) { lit_code_point_t surrogate_code_point = lit_convert_surrogate_pair_to_code_point (character, next_character); output_char_p += lit_code_point_to_utf8 (surrogate_code_point, output_char_p); lit_utf8_iterator_incr (&input_iterator); continue; } } if (lower_case) { character_length = lit_char_to_lower_case (character, character_buffer, LIT_MAXIMUM_OTHER_CASE_LENGTH); } else { character_length = lit_char_to_upper_case (character, character_buffer, LIT_MAXIMUM_OTHER_CASE_LENGTH); } JERRY_ASSERT (character_length >= 1 && character_length <= LIT_MAXIMUM_OTHER_CASE_LENGTH); for (lit_utf8_size_t i = 0; i < character_length; i++) { output_char_p += lit_code_point_to_utf8 (character_buffer[i], output_char_p); } } JERRY_ASSERT (output_start_p + output_length == output_char_p); ecma_string_t *output_string_p = ecma_new_ecma_string_from_utf8 (output_start_p, output_length); ret_value = ecma_make_normal_completion_value (ecma_make_string_value (output_string_p)); MEM_FINALIZE_LOCAL_ARRAY (output_start_p); MEM_FINALIZE_LOCAL_ARRAY (input_start_p); ECMA_FINALIZE (to_string_val); ECMA_FINALIZE (check_coercible_val); return ret_value; } /* ecma_builtin_string_prototype_object_conversion_helper */
/** * [[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 completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_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_completion_value_t completion = ecma_op_to_number (property_desc_p->value); if (ecma_is_completion_value_throw (completion)) { return completion; } JERRY_ASSERT (ecma_is_completion_value_normal (completion) && ecma_is_value_number (ecma_get_completion_value_value (completion))); new_len_num = *ecma_get_number_from_completion_value (completion); ecma_free_completion_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_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE)); } 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_completion_value_t ret_value = ecma_make_empty_completion_value (); // 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_completion_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_completion_value_normal_true (succeeded)) { JERRY_ASSERT (ecma_is_completion_value_normal_false (succeeded) || ecma_is_completion_value_throw (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_completion_value_t delete_succeeded = ecma_op_object_delete (obj_p, index_string_p, false); ecma_deref_ecma_string (index_string_p); if (ecma_is_completion_value_normal_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_completion_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_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (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_completion_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_completion_value_normal_true (completion_set_not_writable)); } ret_value = ecma_make_simple_completion_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_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, false); // d. JERRY_ASSERT (ecma_is_completion_value_normal_true (succeeded) || ecma_is_completion_value_normal_false (succeeded)); if (ecma_is_completion_value_normal_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_completion_value (ECMA_SIMPLE_VALUE_TRUE); } JERRY_UNREACHABLE (); } /* ecma_op_array_object_define_own_property */
/** * The Error.prototype object's 'toString' routine * * See also: * ECMA-262 v5, 15.11.4.4 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_error_prototype_object_to_string (ecma_value_t this_arg) /**< this argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 2. if (!ecma_is_value_object (this_arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } 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_completion_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_normal_completion_value (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_completion_value_normal (name_to_str_completion))) { ret_value = ecma_copy_completion_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_completion_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_normal_completion_value (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_completion_value_normal (msg_to_str_completion))) { ret_value = ecma_copy_completion_value (msg_to_str_completion); } else { ecma_string_t *name_string_p = ecma_get_string_from_completion_value (name_to_str_completion); ecma_string_t *msg_string_p = ecma_get_string_from_completion_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 size = (ecma_string_get_size (name_string_p) + ecma_string_get_size (msg_string_p) + lit_get_magic_string_size (LIT_MAGIC_STRING_COLON_CHAR) + lit_get_magic_string_size (LIT_MAGIC_STRING_SPACE_CHAR)); const ssize_t buffer_size = (ssize_t) size; ssize_t buffer_size_left = buffer_size; MEM_DEFINE_LOCAL_ARRAY (ret_str_buffer, buffer_size, lit_utf8_byte_t); lit_utf8_byte_t *ret_str_buffer_p = ret_str_buffer; ssize_t bytes = ecma_string_to_utf8_string (name_string_p, ret_str_buffer_p, buffer_size_left); JERRY_ASSERT (bytes >= 0 && buffer_size_left - bytes >= 0); buffer_size_left -= bytes; ret_str_buffer_p = ret_str_buffer + buffer_size - buffer_size_left; ret_str_buffer_p = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_COLON_CHAR, ret_str_buffer_p, buffer_size_left); buffer_size_left = buffer_size - (ret_str_buffer_p - ret_str_buffer); JERRY_ASSERT (buffer_size_left >= 0); ret_str_buffer_p = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_SPACE_CHAR, ret_str_buffer_p, buffer_size_left); buffer_size_left = buffer_size - (ret_str_buffer_p - ret_str_buffer); JERRY_ASSERT (buffer_size_left >= 0); bytes = ecma_string_to_utf8_string (msg_string_p, ret_str_buffer_p, buffer_size_left); JERRY_ASSERT (bytes >= 0 && buffer_size_left - bytes >= 0); buffer_size_left -= bytes; JERRY_ASSERT (buffer_size_left >= 0); ret_str_p = ecma_new_ecma_string_from_utf8 (ret_str_buffer, (jerry_api_size_t) (buffer_size - buffer_size_left)); MEM_FINALIZE_LOCAL_ARRAY (ret_str_buffer); } ret_value = ecma_make_normal_completion_value (ecma_make_string_value (ret_str_p)); } ecma_free_completion_value (msg_to_str_completion); ECMA_FINALIZE (msg_get_ret_value); ecma_deref_ecma_string (message_magic_string_p); } ecma_free_completion_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 */