Example #1
0
/**
 * 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 */
Example #3
0
/**
 * 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 */
Example #4
0
/**
 * 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 */
Example #10
0
/**
 * 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 */
Example #13
0
/**
 * 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 */
Example #18
0
/**
 * 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 */
Example #19
0
/**
 * 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 */
Example #20
0
/**
 * 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 */
Example #25
0
/**
 * 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 */
Example #28
0
/**
 * [[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 */