/**
 * ECMA-reference constructor.
 *
 * @return ECMA-reference
 *         Returned value must be freed through ecma_free_reference.
 */
ecma_reference_t
ecma_make_reference (ecma_value_t base, /**< base value */
                     ecma_string_t *name_p, /**< referenced name */
                     bool is_strict) /**< strict reference flag */
{
  ecma_ref_ecma_string (name_p);

  ecma_reference_t ref;
  ref.base = ecma_copy_value (base);
  ref.is_strict = (is_strict != 0);

  ECMA_SET_POINTER (ref.referenced_name_cp, name_p);

  return ref;
} /* ecma_make_reference */
/**
 * Standard ecma-error object constructor.
 *
 * @return pointer to ecma-object representing specified error
 *         with reference counter set to one.
 */
ecma_object_t *
ecma_new_standard_error_with_message (ecma_standard_error_t error_type, /**< native error type */
                                      ecma_string_t *message_string_p) /**< message string */
{
  ecma_object_t *new_error_obj_p = ecma_new_standard_error (error_type);

  ecma_string_t *message_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE);
  ecma_property_t *prop_p = ecma_create_named_data_property (new_error_obj_p,
                                                             message_magic_string_p,
                                                             ECMA_PROPERTY_CONFIGURABLE_WRITABLE);

  ecma_ref_ecma_string (message_string_p);
  ecma_set_named_data_property_value (prop_p,
                                      ecma_make_string_value (message_string_p));
  ecma_deref_ecma_string (message_magic_string_p);

  return new_error_obj_p;
} /* ecma_new_standard_error_with_message */
Exemple #3
0
/**
 * Send string representation of exception to the client.
 *
 * @return true - if the data sent successfully to the debugger client,
 *         false - otherwise
 */
bool
jerry_debugger_send_exception_string (void)
{
  ecma_string_t *string_p = NULL;

  ecma_value_t exception_value = JERRY_CONTEXT (error_value);

  if (ecma_is_value_object (exception_value))
  {
    string_p = jerry_debugger_exception_object_to_string (exception_value);

    if (string_p == NULL)
    {
      string_p = ecma_get_string_from_value (ecma_builtin_helper_object_to_string (exception_value));
    }
  }
  else if (ecma_is_value_string (exception_value))
  {
    string_p = ecma_get_string_from_value (exception_value);
    ecma_ref_ecma_string (string_p);
  }
  else
  {
    exception_value = ecma_op_to_string (exception_value);
    string_p = ecma_get_string_from_value (exception_value);
  }

  ECMA_STRING_TO_UTF8_STRING (string_p, string_data_p, string_size);

  bool result = jerry_debugger_send_string (JERRY_DEBUGGER_EXCEPTION_STR,
                                            JERRY_DEBUGGER_NO_SUBTYPE,
                                            string_data_p,
                                            string_size);

  ECMA_FINALIZE_UTF8_STRING (string_data_p, string_size);

  ecma_deref_ecma_string (string_p);
  return result;
} /* jerry_debugger_send_exception_string */
/**
 * [[GetOwnProperty]] ecma String object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 15.5.5.2
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value
 */
ecma_property_t *
ecma_op_string_object_get_own_property (ecma_object_t *obj_p, /**< a String object */
                                        ecma_string_t *property_name_p) /**< property name */
{
  JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_STRING);

  // 1.
  ecma_property_t *prop_p = ecma_op_general_object_get_own_property (obj_p, property_name_p);

  // 2.
  if (prop_p != NULL)
  {
    return prop_p;
  }

  // 3., 5.
  uint32_t uint32_index;
  ecma_string_t *new_prop_name_p;

  if (ECMA_STRING_GET_CONTAINER (property_name_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
  {
    uint32_index = property_name_p->u.uint32_number;

    new_prop_name_p = property_name_p;
    ecma_ref_ecma_string (new_prop_name_p);
  }
  else
  {
    ecma_number_t index = ecma_string_to_number (property_name_p);
    uint32_index = ecma_number_to_uint32 (index);

    ecma_string_t *to_str_p = ecma_new_ecma_string_from_uint32 (uint32_index);

    bool are_equal = ecma_compare_ecma_strings (to_str_p, property_name_p);

    if (!are_equal)
    {
      ecma_deref_ecma_string (to_str_p);

      return NULL;
    }
    else
    {
      new_prop_name_p = to_str_p;
    }
  }

  // 4.
  ecma_property_t *prim_value_prop_p = ecma_get_internal_property (obj_p,
                                                                   ECMA_INTERNAL_PROPERTY_ECMA_VALUE);
  ecma_string_t *prim_value_str_p;
  prim_value_str_p = ecma_get_string_from_value (ecma_get_internal_property_value (prim_value_prop_p));

  // 6.
  ecma_length_t length = ecma_string_get_length (prim_value_str_p);

  ecma_property_t *new_prop_p;

  if (uint32_index >= (uint32_t) length)
  {
    // 7.
    new_prop_p = NULL;
  }
  else
  {
    // 8.
    ecma_char_t c = ecma_string_get_char_at_pos (prim_value_str_p, uint32_index);

    // 9.
    ecma_string_t *new_prop_str_value_p = ecma_new_ecma_string_from_code_unit (c);

    new_prop_p = ecma_create_named_data_property (obj_p,
                                                  new_prop_name_p,
                                                  ECMA_PROPERTY_FLAG_ENUMERABLE);

    ecma_set_named_data_property_value (new_prop_p,
                                        ecma_make_string_value (new_prop_str_value_p));
  }

  ecma_deref_ecma_string (new_prop_name_p);

  return new_prop_p;
} /* ecma_op_string_object_get_own_property */
/**
 * The RegExp.prototype object's 'compile' routine
 *
 * See also:
 *          ECMA-262 v5, B.2.5.1
 *
 * @return undefined        - if compiled successfully
 *         error ecma value - otherwise
 *
 *         Returned value must be freed with ecma_free_value.
 */
static ecma_value_t
ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument */
                                       ecma_value_t pattern_arg, /**< pattern or RegExp object */
                                       ecma_value_t flags_arg) /**< flags */
{
  ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  if (!ecma_is_value_object (this_arg)
      || ecma_object_get_class_name (ecma_get_object_from_value (this_arg)) != LIT_MAGIC_STRING_REGEXP_UL)
  {
    ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Incomplete RegExp type"));
  }
  else
  {
    ecma_string_t *pattern_string_p = NULL;
    uint16_t flags = 0;

    if (ecma_is_value_object (pattern_arg)
        && ecma_object_get_class_name (ecma_get_object_from_value (pattern_arg)) == LIT_MAGIC_STRING_REGEXP_UL)
    {
      if (!ecma_is_value_undefined (flags_arg))
      {
        ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument of RegExp compile."));
      }
      else
      {
        /* Compile from existing RegExp pbject. */
        ecma_object_t *target_p = ecma_get_object_from_value (pattern_arg);

        /* Get source. */
        ecma_string_t *magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE);
        ecma_property_t *prop_p = ecma_op_object_get_property (target_p, magic_string_p);
        pattern_string_p = ecma_get_string_from_value (ecma_get_named_data_property_value (prop_p));
        ecma_deref_ecma_string (magic_string_p);

        /* Get flags. */
        magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL);
        prop_p = ecma_op_object_get_property (target_p, magic_string_p);

        if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p)))
        {
          flags |= RE_FLAG_GLOBAL;
        }

        ecma_deref_ecma_string (magic_string_p);
        magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL);
        prop_p = ecma_op_object_get_property (target_p, magic_string_p);

        if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p)))
        {
          flags |= RE_FLAG_IGNORE_CASE;
        }

        ecma_deref_ecma_string (magic_string_p);
        magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE);
        prop_p = ecma_op_object_get_property (target_p, magic_string_p);

        if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p)))
        {
          flags |= RE_FLAG_MULTILINE;
        }

        ecma_deref_ecma_string (magic_string_p);

        ECMA_TRY_CATCH (obj_this, ecma_op_to_object (this_arg), ret_value);
        ecma_object_t *this_obj_p = ecma_get_object_from_value (obj_this);

        /* Get bytecode property. */
        ecma_property_t *bc_prop_p = ecma_get_internal_property (this_obj_p,
                                                                 ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE);

        /* TODO: We currently have to re-compile the bytecode, because
         * we can't copy it without knowing its length. */
        const re_compiled_code_t *new_bc_p = NULL;
        ecma_value_t bc_comp = re_compile_bytecode (&new_bc_p, pattern_string_p, flags);
        /* Should always succeed, since we're compiling from a source that has been compiled previously. */
        JERRY_ASSERT (ecma_is_value_empty (bc_comp));

        re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t,
                                                                        ecma_get_internal_property_value (bc_prop_p));
        if (old_bc_p != NULL)
        {
          /* Free the old bytecode */
          ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p);
        }

        ECMA_SET_INTERNAL_VALUE_POINTER (ECMA_PROPERTY_VALUE_PTR (bc_prop_p)->value, new_bc_p);

        re_initialize_props (this_obj_p, pattern_string_p, flags);

        ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);

        ECMA_FINALIZE (obj_this);
      }
    }
    else
    {
      /* Get source string. */
      if (!ecma_is_value_undefined (pattern_arg))
      {
        ECMA_TRY_CATCH (regexp_str_value,
                        ecma_op_to_string (pattern_arg),
                        ret_value);

        if (ecma_string_is_empty (ecma_get_string_from_value (regexp_str_value)))
        {
          pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
        }
        else
        {
          pattern_string_p = ecma_get_string_from_value (regexp_str_value);
          ecma_ref_ecma_string (pattern_string_p);
        }

        ECMA_FINALIZE (regexp_str_value);
      }
      else
      {
        pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
      }

      /* Parse flags. */
      if (ecma_is_value_empty (ret_value) && !ecma_is_value_undefined (flags_arg))
      {
        ECMA_TRY_CATCH (flags_str_value,
                        ecma_op_to_string (flags_arg),
                        ret_value);

        ECMA_TRY_CATCH (flags_dummy,
                        re_parse_regexp_flags (ecma_get_string_from_value (flags_str_value), &flags),
                        ret_value);
        ECMA_FINALIZE (flags_dummy);
        ECMA_FINALIZE (flags_str_value);
      }

      if (ecma_is_value_empty (ret_value))
      {
        ECMA_TRY_CATCH (obj_this, ecma_op_to_object (this_arg), ret_value);
        ecma_object_t *this_obj_p = ecma_get_object_from_value (obj_this);

        ecma_property_t *bc_prop_p = ecma_get_internal_property (this_obj_p,
                                                                 ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE);
        /* Try to compile bytecode from new source. */
        const re_compiled_code_t *new_bc_p = NULL;
        ECMA_TRY_CATCH (bc_dummy,
                        re_compile_bytecode (&new_bc_p, pattern_string_p, flags),
                        ret_value);

        re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t,
                                                                        ecma_get_internal_property_value (bc_prop_p));

        if (old_bc_p != NULL)
        {
          /* Free the old bytecode */
          ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p);
        }

        ECMA_SET_INTERNAL_VALUE_POINTER (ECMA_PROPERTY_VALUE_PTR (bc_prop_p)->value, new_bc_p);
        re_initialize_props (this_obj_p, pattern_string_p, flags);
        ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);

        ECMA_FINALIZE (bc_dummy);

        ECMA_FINALIZE (obj_this);
      }

      if (pattern_string_p != NULL)
      {
        ecma_deref_ecma_string (pattern_string_p);
      }
    }
  }

  return ret_value;
} /* ecma_builtin_regexp_prototype_compile */
/**
 * ToString operation.
 *
 * See also:
 *          ECMA-262 v5, 9.8
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value
 */
ecma_value_t
ecma_op_to_string (ecma_value_t value) /**< ecma value */
{
  ecma_check_value_type_is_spec_defined (value);

  if (unlikely (ecma_is_value_object (value)))
  {
    ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

    ECMA_TRY_CATCH (prim_value,
                    ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_STRING),
                    ret_value);

    ret_value = ecma_op_to_string (prim_value);

    ECMA_FINALIZE (prim_value);

    return ret_value;
  }
  else
  {
    ecma_string_t *res_p = NULL;

    if (ecma_is_value_string (value))
    {
      res_p = ecma_get_string_from_value (value);
      ecma_ref_ecma_string (res_p);
    }
    else if (ecma_is_value_integer_number (value))
    {
      ecma_integer_value_t num = ecma_get_integer_from_value (value);

      if (num < 0)
      {
        res_p = ecma_new_ecma_string_from_number ((ecma_number_t) num);
      }
      else
      {
        res_p = ecma_new_ecma_string_from_uint32 ((uint32_t) num);
      }
    }
    else if (ecma_is_value_float_number (value))
    {
      ecma_number_t num = ecma_get_float_from_value (value);
      res_p = ecma_new_ecma_string_from_number (num);
    }
    else if (ecma_is_value_undefined (value))
    {
      res_p = ecma_get_magic_string (LIT_MAGIC_STRING_UNDEFINED);
    }
    else if (ecma_is_value_null (value))
    {
      res_p = ecma_get_magic_string (LIT_MAGIC_STRING_NULL);
    }
    else
    {
      JERRY_ASSERT (ecma_is_value_boolean (value));

      if (ecma_is_value_true (value))
      {
        res_p = ecma_get_magic_string (LIT_MAGIC_STRING_TRUE);
      }
      else
      {
        res_p = ecma_get_magic_string (LIT_MAGIC_STRING_FALSE);
      }
    }

    return ecma_make_string_value (res_p);
  }
} /* ecma_op_to_string */
/**
 * Concatenate ecma-strings
 *
 * @return concatenation of two ecma-strings
 */
ecma_string_t *
ecma_concat_ecma_strings (ecma_string_t *string1_p, /**< first ecma-string */
                          ecma_string_t *string2_p) /**< second ecma-string */
{
  JERRY_ASSERT (string1_p != NULL
                && string2_p != NULL);

  if (ecma_string_is_empty (string1_p))
  {
    ecma_ref_ecma_string (string2_p);
    return string2_p;
  }
  else if (ecma_string_is_empty (string2_p))
  {
    ecma_ref_ecma_string (string1_p);
    return string1_p;
  }

  const lit_utf8_byte_t *utf8_string1_p, *utf8_string2_p;
  lit_utf8_size_t utf8_string1_size, utf8_string2_size;
  lit_utf8_size_t utf8_string1_length, utf8_string2_length;

  lit_utf8_byte_t uint32_to_string_buffer1[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32];
  lit_utf8_byte_t uint32_to_string_buffer2[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32];

  switch (ECMA_STRING_GET_CONTAINER (string1_p))
  {
    case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING:
    {
      utf8_string1_p = (lit_utf8_byte_t *) (string1_p + 1);
      utf8_string1_size = string1_p->u.utf8_string.size;
      utf8_string1_length = string1_p->u.utf8_string.length;
      break;
    }
    case ECMA_STRING_CONTAINER_UINT32_IN_DESC:
    {
      utf8_string1_size = ecma_uint32_to_utf8_string (string1_p->u.uint32_number,
                                                      uint32_to_string_buffer1,
                                                      ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
      utf8_string1_p = uint32_to_string_buffer1;
      utf8_string1_length = utf8_string1_size;
      break;
    }
    case ECMA_STRING_CONTAINER_MAGIC_STRING:
    {
      utf8_string1_p = lit_get_magic_string_utf8 (string1_p->u.magic_string_id);
      utf8_string1_size = lit_get_magic_string_size (string1_p->u.magic_string_id);
      utf8_string1_length = utf8_string1_size;
      break;
    }
    default:
    {
      JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);

      utf8_string1_p = lit_get_magic_string_ex_utf8 (string1_p->u.magic_string_id);
      utf8_string1_size = lit_get_magic_string_ex_size (string1_p->u.magic_string_id);
      utf8_string1_length = utf8_string1_size;
      break;
    }
  }

  switch (ECMA_STRING_GET_CONTAINER (string2_p))
  {
    case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING:
    {
      utf8_string2_p = (lit_utf8_byte_t *) (string2_p + 1);
      utf8_string2_size = string2_p->u.utf8_string.size;
      utf8_string2_length = string2_p->u.utf8_string.length;
      break;
    }
    case ECMA_STRING_CONTAINER_UINT32_IN_DESC:
    {
      utf8_string2_size = ecma_uint32_to_utf8_string (string2_p->u.uint32_number,
                                                      uint32_to_string_buffer2,
                                                      ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
      utf8_string2_p = uint32_to_string_buffer2;
      utf8_string2_length = utf8_string2_size;
      break;
    }
    case ECMA_STRING_CONTAINER_MAGIC_STRING:
    {
      utf8_string2_p = lit_get_magic_string_utf8 (string2_p->u.magic_string_id);
      utf8_string2_size = lit_get_magic_string_size (string2_p->u.magic_string_id);
      utf8_string2_length = utf8_string2_size;
      break;
    }
    default:
    {
      JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string2_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX);

      utf8_string2_p = lit_get_magic_string_ex_utf8 (string2_p->u.magic_string_id);
      utf8_string2_size = lit_get_magic_string_ex_size (string2_p->u.magic_string_id);
      utf8_string2_length = utf8_string2_size;
      break;
    }
  }

  JERRY_ASSERT (utf8_string1_size > 0);
  JERRY_ASSERT (utf8_string2_size > 0);
  JERRY_ASSERT (utf8_string1_length <= utf8_string1_size);
  JERRY_ASSERT (utf8_string2_length <= utf8_string2_size);

  lit_utf8_size_t new_size = utf8_string1_size + utf8_string2_size;

  JERRY_ASSERT (new_size <= UINT16_MAX);

  ecma_string_t *string_desc_p = jmem_heap_alloc_block (sizeof (ecma_string_t) + new_size);

  string_desc_p->refs_and_container = ECMA_STRING_CONTAINER_HEAP_UTF8_STRING | ECMA_STRING_REF_ONE;
  string_desc_p->hash = lit_utf8_string_hash_combine (string1_p->hash, utf8_string2_p, utf8_string2_size);
  string_desc_p->u.common_field = 0;
  string_desc_p->u.utf8_string.size = (uint16_t) new_size;
  string_desc_p->u.utf8_string.length = (uint16_t) (utf8_string1_length + utf8_string2_length);

  lit_utf8_byte_t *data_p = (lit_utf8_byte_t *) (string_desc_p + 1);
  memcpy (data_p, utf8_string1_p, utf8_string1_size);
  memcpy (data_p + utf8_string1_size, utf8_string2_p, utf8_string2_size);

  return string_desc_p;
} /* ecma_concat_ecma_strings */
/**
 * Handle calling [[Construct]] of built-in RegExp object
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
 */
ecma_value_t
ecma_builtin_regexp_dispatch_construct (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_value_t pattern_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
    ecma_value_t flags_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);

    if (arguments_list_len > 0)
    {
        /* pattern string or RegExp object */
        pattern_value = arguments_list_p[0];

        if (arguments_list_len > 1)
        {
            flags_value = arguments_list_p[1];
        }
    }

    if (ecma_is_value_object (pattern_value)
            && ecma_object_get_class_name (ecma_get_object_from_value (pattern_value)) == LIT_MAGIC_STRING_REGEXP_UL)
    {
        if (ecma_is_value_undefined (flags_value))
        {
            ret_value = ecma_copy_value (pattern_value);
        }
        else
        {
            ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument of RegExp call."));
        }
    }
    else
    {
        ecma_string_t *pattern_string_p = NULL;
        ecma_string_t *flags_string_p = NULL;

        if (!ecma_is_value_undefined (pattern_value))
        {
            ECMA_TRY_CATCH (regexp_str_value,
                            ecma_op_to_string (pattern_value),
                            ret_value);

            if (ecma_string_is_empty (ecma_get_string_from_value (regexp_str_value)))
            {
                pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
            }
            else
            {
                pattern_string_p = ecma_get_string_from_value (regexp_str_value);
                ecma_ref_ecma_string (pattern_string_p);
            }

            ECMA_FINALIZE (regexp_str_value);
        }
        else
        {
            pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
        }

        if (ecma_is_value_empty (ret_value) && !ecma_is_value_undefined (flags_value))
        {
            ECMA_TRY_CATCH (flags_str_value,
                            ecma_op_to_string (flags_value),
                            ret_value);

            flags_string_p = ecma_get_string_from_value (flags_str_value);
            ecma_ref_ecma_string (flags_string_p);

            ECMA_FINALIZE (flags_str_value);
        }

        if (ecma_is_value_empty (ret_value))
        {
            ret_value = ecma_op_create_regexp_object (pattern_string_p, flags_string_p);
        }

        if (pattern_string_p != NULL)
        {
            ecma_deref_ecma_string (pattern_string_p);
        }

        if (flags_string_p != NULL)
        {
            ecma_deref_ecma_string (flags_string_p);
        }
    }

    return ret_value;
} /* ecma_builtin_regexp_dispatch_construct */
Exemple #9
0
/**
 * Get backtrace. The backtrace is an array of strings where
 * each string contains the position of the corresponding frame.
 * The array length is zero if the backtrace is not available.
 *
 * @return array ecma value
 */
ecma_value_t
vm_get_backtrace (uint32_t max_depth) /**< maximum backtrace depth, 0 = unlimited */
{
#ifdef JERRY_ENABLE_LINE_INFO
  ecma_value_t result_array = ecma_op_create_array_object (NULL, 0, false);

  if (max_depth == 0)
  {
    max_depth = UINT32_MAX;
  }

  vm_frame_ctx_t *context_p = JERRY_CONTEXT (vm_top_context_p);
  ecma_object_t *array_p = ecma_get_object_from_value (result_array);
  uint32_t index = 0;

  while (context_p != NULL)
  {
    if (context_p->resource_name == ECMA_VALUE_UNDEFINED)
    {
      context_p = context_p->prev_context_p;
      continue;
    }

    ecma_string_t *str_p = ecma_get_string_from_value (context_p->resource_name);

    if (ecma_string_is_empty (str_p))
    {
      const char *unknown_str_p = "<unknown>:";
      str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) unknown_str_p,
                                              (lit_utf8_size_t) strlen (unknown_str_p));
    }
    else
    {
      ecma_ref_ecma_string (str_p);
      str_p = ecma_append_magic_string_to_string (str_p, LIT_MAGIC_STRING_COLON_CHAR);
    }

    ecma_string_t *line_str_p = ecma_new_ecma_string_from_uint32 (context_p->current_line);
    str_p = ecma_concat_ecma_strings (str_p, line_str_p);
    ecma_deref_ecma_string (line_str_p);

    ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index);
    ecma_property_value_t *prop_value_p;
    prop_value_p = ecma_create_named_data_property (array_p,
                                                    index_str_p,
                                                    ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
                                                    NULL);
    ecma_deref_ecma_string (index_str_p);

    prop_value_p->value = ecma_make_string_value (str_p);

    context_p = context_p->prev_context_p;
    index++;

    if (index >= max_depth)
    {
      break;
    }
  }

  if (index > 0)
  {
    JERRY_ASSERT (ecma_get_object_type (array_p) == ECMA_OBJECT_TYPE_ARRAY);

    ((ecma_extended_object_t *) array_p)->u.array.length = index;
  }

  return result_array;
#else /* !JERRY_ENABLE_LINE_INFO */
  JERRY_UNUSED (max_depth);

  return ecma_op_create_array_object (NULL, 0, false);
#endif /* JERRY_ENABLE_LINE_INFO */
} /* vm_get_backtrace */