/**
 * Handle calling [[Construct]] of built-in Object object
 *
 * @return completion-value
 */
ecma_completion_value_t
ecma_builtin_object_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
                                        ecma_length_t arguments_list_len) /**< number of arguments */
{
  JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);

  if (arguments_list_len == 0)
  {
    ecma_object_t *obj_p = ecma_op_create_object_object_noarg ();

    return ecma_make_normal_completion_value (ecma_make_object_value (obj_p));
  }
  else
  {
    ecma_completion_value_t new_obj_value = ecma_op_create_object_object_arg (arguments_list_p[0]);

    if (!ecma_is_completion_value_normal (new_obj_value))
    {
      return new_obj_value;
    }
    else
    {
      return ecma_make_normal_completion_value (ecma_get_completion_value_value (new_obj_value));
    }
  }
} /* ecma_builtin_object_dispatch_construct */
/**
 * 'Object' object creation operation with one argument.
 *
 * See also: ECMA-262 v5, 15.2.2.1
 *
 * @return pointer to newly created 'Object' object
 */
ecma_completion_value_t
ecma_op_create_object_object_arg (ecma_value_t value) /**< argument of constructor */
{
  ecma_check_value_type_is_spec_defined (value);

  if (ecma_is_value_object (value)
      || ecma_is_value_number (value)
      || ecma_is_value_string (value)
      || ecma_is_value_boolean (value))
  {
    // 1.b, 1.c, 1.d
    return ecma_op_to_object (value);
  }
  else
  {
    // 2.
    JERRY_ASSERT (ecma_is_value_undefined (value)
                  || ecma_is_value_null (value));

    ecma_object_t *obj_p = ecma_op_create_object_object_noarg ();

    return ecma_make_normal_completion_value (ecma_make_object_value (obj_p));
  }
} /* ecma_op_create_object_object_arg */
/**
 * Lazy instantation of non-builtin ecma function object's properties
 *
 * Warning:
 *         Only non-configurable properties could be instantiated lazily in this function,
 *         as configurable properties could be deleted and it would be incorrect
 *         to reinstantiate them in the function in second time.
 *
 * @return pointer to newly instantiated property, if a property was instantiated,
 *         NULL - otherwise
 */
ecma_property_t *
ecma_op_function_try_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */
                                                ecma_string_t *property_name_p) /**< property name */
{
  static const char prototype_str_p[] = "prototype";

  JERRY_ASSERT (!ecma_get_object_is_builtin (object_p));

  ecma_string_container_t container = ECMA_STRING_GET_CONTAINER (property_name_p);

  /* Check whether the property_name_p is prototype */
  if (container == ECMA_STRING_CONTAINER_MAGIC_STRING)
  {
    if (property_name_p->u.magic_string_id != LIT_MAGIC_STRING_PROTOTYPE)
    {
      return NULL;
    }
  }
  else if (container != ECMA_STRING_CONTAINER_HEAP_UTF8_STRING
           || property_name_p->u.utf8_string.size != (sizeof (prototype_str_p) - 1))
  {
    return NULL;
  }
  else
  {
    if (strncmp ((char *) (property_name_p + 1), prototype_str_p, (sizeof (prototype_str_p) - 1)) != 0)
    {
      return NULL;
    }
  }

  /* ECMA-262 v5, 13.2, 16-18 */

  /* 16. */
  ecma_object_t *proto_object_p = ecma_op_create_object_object_noarg ();

  /* 17. */
  ecma_string_t *magic_string_constructor_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR);

  ecma_property_value_t *constructor_prop_value_p;
  constructor_prop_value_p = ecma_create_named_data_property (proto_object_p,
                                                              magic_string_constructor_p,
                                                              ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
                                                              NULL);

  constructor_prop_value_p->value = ecma_make_object_value (object_p);

  ecma_deref_ecma_string (magic_string_constructor_p);

  /* 18. */
  ecma_property_t *prototype_prop_p;
  ecma_property_value_t *prototype_prop_value_p;
  prototype_prop_value_p = ecma_create_named_data_property (object_p,
                                                            property_name_p,
                                                            ECMA_PROPERTY_FLAG_WRITABLE,
                                                            &prototype_prop_p);

  prototype_prop_value_p->value = ecma_make_object_value (proto_object_p);

  ecma_deref_object (proto_object_p);

  return prototype_prop_p;
} /* ecma_op_function_try_lazy_instantiate_property */
/**
 * Arguments object creation operation.
 *
 * See also: ECMA-262 v5, 10.6
 */
void
ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function */
                                 ecma_object_t *lex_env_p, /**< lexical environment the Arguments
                                                                object is created for */
                                 const ecma_value_t *arguments_list_p, /**< arguments list */
                                 ecma_length_t arguments_number, /**< length of arguments list */
                                 const ecma_compiled_code_t *bytecode_data_p) /**< byte code */
{
  // 2., 3., 6.
  ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);

  ecma_object_t *obj_p = ecma_create_object (prototype_p, false, true, ECMA_OBJECT_TYPE_GENERAL);

  ecma_deref_object (prototype_p);

  // 11.a, 11.b
  for (ecma_length_t indx = 0;
       indx < arguments_number;
       indx++)
  {
    ecma_value_t completion;
    ecma_string_t *indx_string_p = ecma_new_ecma_string_from_uint32 (indx);

    completion = ecma_builtin_helper_def_prop (obj_p,
                                               indx_string_p,
                                               arguments_list_p[indx],
                                               true, /* Writable */
                                               true, /* Enumerable */
                                               true, /* Configurable */
                                               false); /* Failure handling */

    JERRY_ASSERT (ecma_is_value_true (completion));

    ecma_deref_ecma_string (indx_string_p);
  }

  bool is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0;

  // 1.

  // 4.
  ecma_property_t *class_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_CLASS);
  ECMA_PROPERTY_VALUE_PTR (class_prop_p)->value = LIT_MAGIC_STRING_ARGUMENTS_UL;

  // 7.
  ecma_string_t *length_magic_string_p = ecma_new_ecma_length_string ();
  ecma_value_t completion = ecma_builtin_helper_def_prop (obj_p,
                                                          length_magic_string_p,
                                                          ecma_make_uint32_value (arguments_number),
                                                          true, /* Writable */
                                                          false, /* Enumerable */
                                                          true, /* Configurable */
                                                          false); /* Failure handling */

  JERRY_ASSERT (ecma_is_value_true (completion));
  ecma_deref_ecma_string (length_magic_string_p);

  ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();

  if (bytecode_data_p != NULL)
  {
    ecma_length_t formal_params_number;
    jmem_cpointer_t *literal_p;

    if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
    {
      cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_data_p;
      uint8_t *byte_p = (uint8_t *) bytecode_data_p;

      formal_params_number = args_p->argument_end;
      literal_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint16_arguments_t));
    }
    else
    {
      cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_data_p;
      uint8_t *byte_p = (uint8_t *) bytecode_data_p;

      formal_params_number = args_p->argument_end;
      literal_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint8_arguments_t));
    }

    if (!is_strict
        && arguments_number > 0
        && formal_params_number > 0)
    {
      // 8.
      ecma_object_t *map_p = ecma_op_create_object_object_noarg ();

      // 11.c
      for (uint32_t indx = 0;
           indx < formal_params_number;
           indx++)
      {
        // i.
        if (literal_p[indx] == JMEM_CP_NULL)
        {
          continue;
        }

        ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, literal_p[indx]);
        ecma_string_t *indx_string_p = ecma_new_ecma_string_from_uint32 ((uint32_t) indx);

        prop_desc.is_value_defined = true;
        prop_desc.value = ecma_make_string_value (name_p);

        prop_desc.is_configurable_defined = true;
        prop_desc.is_configurable = true;

        completion = ecma_op_object_define_own_property (map_p,
                                                         indx_string_p,
                                                         &prop_desc,
                                                         false);
        JERRY_ASSERT (ecma_is_value_true (completion));

        ecma_deref_ecma_string (indx_string_p);
      }

      // 12.
      ecma_set_object_type (obj_p, ECMA_OBJECT_TYPE_ARGUMENTS);

      /*
       * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_ARGUMENTS type.
       *
       * See also: ecma_object_get_class_name
       */
      ecma_delete_property (obj_p, class_prop_p);

      ecma_property_t *parameters_map_prop_p = ecma_create_internal_property (obj_p,
                                                                              ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP);
      ECMA_SET_INTERNAL_VALUE_POINTER (ECMA_PROPERTY_VALUE_PTR (parameters_map_prop_p)->value, map_p);

      ecma_property_t *scope_prop_p = ecma_create_internal_property (map_p,
                                                                     ECMA_INTERNAL_PROPERTY_SCOPE);
      ECMA_SET_INTERNAL_VALUE_POINTER (ECMA_PROPERTY_VALUE_PTR (scope_prop_p)->value, lex_env_p);

      ecma_deref_object (map_p);
    }
  }

  // 13.
  if (!is_strict)
  {
    ecma_string_t *callee_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE);

    completion = ecma_builtin_helper_def_prop (obj_p,
                                               callee_magic_string_p,
                                               ecma_make_object_value (func_obj_p),
                                               true, /* Writable */
                                               false, /* Enumerable */
                                               true, /* Configurable */
                                               false); /* Failure handling */

    JERRY_ASSERT (ecma_is_value_true (completion));

    ecma_deref_ecma_string (callee_magic_string_p);
  }
  else
  {
    ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);

    // 14.
    prop_desc = ecma_make_empty_property_descriptor ();
    {
      prop_desc.is_get_defined = true;
      prop_desc.get_p = thrower_p;

      prop_desc.is_set_defined = true;
      prop_desc.set_p = thrower_p;

      prop_desc.is_enumerable_defined = true;
      prop_desc.is_enumerable = false;

      prop_desc.is_configurable_defined = true;
      prop_desc.is_configurable = false;
    }

    ecma_string_t *callee_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE);

    completion = ecma_op_object_define_own_property (obj_p,
                                                     callee_magic_string_p,
                                                     &prop_desc,
                                                     false);
    JERRY_ASSERT (ecma_is_value_true (completion));
    ecma_deref_ecma_string (callee_magic_string_p);

    ecma_string_t *caller_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER);
    completion = ecma_op_object_define_own_property (obj_p,
                                                     caller_magic_string_p,
                                                     &prop_desc,
                                                     false);
    JERRY_ASSERT (ecma_is_value_true (completion));
    ecma_deref_ecma_string (caller_magic_string_p);

    ecma_deref_object (thrower_p);
  }

  ecma_string_t *arguments_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);

  if (is_strict)
  {
    ecma_op_create_immutable_binding (lex_env_p, arguments_string_p);
    ecma_op_initialize_immutable_binding (lex_env_p,
                                          arguments_string_p,
                                          ecma_make_object_value (obj_p));
  }
  else
  {
    ecma_value_t completion = ecma_op_create_mutable_binding (lex_env_p,
                                                              arguments_string_p,
                                                              false);
    JERRY_ASSERT (ecma_is_value_empty (completion));

    completion = ecma_op_set_mutable_binding (lex_env_p,
                                              arguments_string_p,
                                              ecma_make_object_value (obj_p),
                                              false);

    JERRY_ASSERT (ecma_is_value_empty (completion));
  }

  ecma_deref_ecma_string (arguments_string_p);
  ecma_deref_object (obj_p);
} /* ecma_op_create_arguments_object */
Example #5
0
/**
 * FromPropertyDescriptor operation.
 *
 * See also:
 *          ECMA-262 v5, 8.10.4
 *
 * @return constructed object
 */
ecma_object_t *
ecma_op_from_property_descriptor (const ecma_property_descriptor_t *src_prop_desc_p) /**< property descriptor */
{
  // 2.
  ecma_object_t *obj_p = ecma_op_create_object_object_noarg ();

  ecma_value_t completion;
  ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
  {
    prop_desc.is_value_defined = true;

    prop_desc.is_writable_defined = true;
    prop_desc.is_writable = true;

    prop_desc.is_enumerable_defined = true;
    prop_desc.is_enumerable = true;

    prop_desc.is_configurable_defined = true;
    prop_desc.is_configurable = true;
  }

  // 3.
  if (src_prop_desc_p->is_value_defined
      || src_prop_desc_p->is_writable_defined)
  {
    JERRY_ASSERT (prop_desc.is_value_defined && prop_desc.is_writable_defined);

    // a.
    prop_desc.value = src_prop_desc_p->value;

    ecma_string_t *value_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_VALUE);
    completion = ecma_op_object_define_own_property (obj_p,
                                                     value_magic_string_p,
                                                     &prop_desc,
                                                     false);
    ecma_deref_ecma_string (value_magic_string_p);
    JERRY_ASSERT (ecma_is_value_true (completion));

    // b.
    const bool is_writable = (src_prop_desc_p->is_writable);
    prop_desc.value = ecma_make_simple_value (is_writable ? ECMA_SIMPLE_VALUE_TRUE
                                                          : ECMA_SIMPLE_VALUE_FALSE);

    ecma_string_t *writable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_WRITABLE);
    completion = ecma_op_object_define_own_property (obj_p,
                                                     writable_magic_string_p,
                                                     &prop_desc,
                                                     false);
    ecma_deref_ecma_string (writable_magic_string_p);
    JERRY_ASSERT (ecma_is_value_true (completion));
  }
  else
  {
    // 4.
    JERRY_ASSERT (src_prop_desc_p->is_get_defined
                  || src_prop_desc_p->is_set_defined);

    // a.
    if (src_prop_desc_p->get_p == NULL)
    {
      prop_desc.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
    }
    else
    {
      prop_desc.value = ecma_make_object_value (src_prop_desc_p->get_p);
    }

    ecma_string_t *get_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GET);
    completion = ecma_op_object_define_own_property (obj_p,
                                                     get_magic_string_p,
                                                     &prop_desc,
                                                     false);
    ecma_deref_ecma_string (get_magic_string_p);
    JERRY_ASSERT (ecma_is_value_true (completion));

    // b.
    if (src_prop_desc_p->set_p == NULL)
    {
      prop_desc.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
    }
    else
    {
      prop_desc.value = ecma_make_object_value (src_prop_desc_p->set_p);
    }

    ecma_string_t *set_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SET);
    completion = ecma_op_object_define_own_property (obj_p,
                                                     set_magic_string_p,
                                                     &prop_desc,
                                                     false);
    ecma_deref_ecma_string (set_magic_string_p);
    JERRY_ASSERT (ecma_is_value_true (completion));
  }

  const bool is_enumerable = src_prop_desc_p->is_enumerable;
  prop_desc.value = ecma_make_simple_value (is_enumerable ? ECMA_SIMPLE_VALUE_TRUE
                                            : ECMA_SIMPLE_VALUE_FALSE);

  ecma_string_t *enumerable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ENUMERABLE);
  completion = ecma_op_object_define_own_property (obj_p,
                                                   enumerable_magic_string_p,
                                                   &prop_desc,
                                                   false);
  ecma_deref_ecma_string (enumerable_magic_string_p);
  JERRY_ASSERT (ecma_is_value_true (completion));

  const bool is_configurable = src_prop_desc_p->is_configurable;
  prop_desc.value = ecma_make_simple_value (is_configurable ? ECMA_SIMPLE_VALUE_TRUE
                                            : ECMA_SIMPLE_VALUE_FALSE);

  ecma_string_t *configurable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONFIGURABLE);
  completion = ecma_op_object_define_own_property (obj_p,
                                                   configurable_magic_string_p,
                                                   &prop_desc,
                                                   false);
  ecma_deref_ecma_string (configurable_magic_string_p);
  JERRY_ASSERT (ecma_is_value_true (completion));

  return obj_p;
} /* ecma_op_from_property_descriptor */
/**
 * Function object creation operation.
 *
 * See also: ECMA-262 v5, 13.2
 *
 * @return pointer to newly created Function object
 */
ecma_object_t*
ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], /**< formal parameters list */
                                ecma_length_t formal_parameters_number, /**< formal parameters list's length */
                                ecma_object_t *scope_p, /**< function's scope */
                                bool is_strict, /**< 'strict' flag */
                                bool do_instantiate_arguments_object, /**< should an Arguments object be instantiated
                                                                       *   for the function object upon call */
                                const vm_instr_t *instrs_p, /**< byte-code array */
                                vm_instr_counter_t first_instr_pos) /**< position of first instruction
                                                                     *   of function's body */
{
  // 1., 4., 13.
  ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);

  ecma_object_t *f = ecma_create_object (prototype_obj_p, true, ECMA_OBJECT_TYPE_FUNCTION);

  ecma_deref_object (prototype_obj_p);

  // 2., 6., 7., 8.
  /*
   * We don't setup [[Get]], [[Call]], [[Construct]], [[HasInstance]] for each function object.
   * Instead we set the object's type to ECMA_OBJECT_TYPE_FUNCTION
   * that defines which version of the routine should be used on demand.
   */

  // 3.
  /*
   * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type.
   *
   * See also: ecma_object_get_class_name
   */

  // 9.
  ecma_property_t *scope_prop_p = ecma_create_internal_property (f, ECMA_INTERNAL_PROPERTY_SCOPE);
  ECMA_SET_POINTER (scope_prop_p->u.internal_property.value, scope_p);

  // 10., 11.
  ecma_property_t *formal_parameters_prop_p = ecma_create_internal_property (f,
                                                                             ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS);
  if (formal_parameters_number != 0)
  {
    /*
     * Reverse formal parameter list
     */
    for (ecma_length_t i = 0; i < formal_parameters_number / 2; i++)
    {
      ecma_string_t *tmp_p = formal_parameter_list_p[i];
      formal_parameter_list_p[i] = formal_parameter_list_p[formal_parameters_number - 1u - i];
      formal_parameter_list_p[formal_parameters_number - 1u - i] = tmp_p;
    }

    ecma_collection_header_t *formal_parameters_collection_p = ecma_new_strings_collection (formal_parameter_list_p,
                                                                                            formal_parameters_number);
    ECMA_SET_POINTER (formal_parameters_prop_p->u.internal_property.value, formal_parameters_collection_p);
  }
  else
  {
    JERRY_ASSERT (formal_parameters_prop_p->u.internal_property.value == ECMA_NULL_POINTER);
  }

  // 12.
  ecma_property_t *bytecode_prop_p = ecma_create_internal_property (f, ECMA_INTERNAL_PROPERTY_CODE_BYTECODE);
  MEM_CP_SET_NON_NULL_POINTER (bytecode_prop_p->u.internal_property.value, instrs_p);

  ecma_property_t *code_prop_p = ecma_create_internal_property (f, ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET);
  code_prop_p->u.internal_property.value = ecma_pack_code_internal_property_value (is_strict,
                                                                                   do_instantiate_arguments_object,
                                                                                   first_instr_pos);

  // 14.
  ecma_number_t* len_p = ecma_alloc_number ();
  *len_p = ecma_uint32_to_number (formal_parameters_number);

  // 15.
  ecma_property_descriptor_t length_prop_desc = ecma_make_empty_property_descriptor ();
  length_prop_desc.is_value_defined = true;
  length_prop_desc.value = ecma_make_number_value (len_p);

  ecma_string_t* magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);
  ecma_completion_value_t completion = ecma_op_object_define_own_property (f,
                                                                           magic_string_length_p,
                                                                           &length_prop_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));

  ecma_dealloc_number (len_p);
  len_p = NULL;

  // 16.
  ecma_object_t *proto_p = ecma_op_create_object_object_noarg ();

  // 17.
  ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
  {
    prop_desc.is_value_defined = true;
    prop_desc.value = ecma_make_object_value (f);

    prop_desc.is_writable_defined = true;
    prop_desc.is_writable = true;

    prop_desc.is_enumerable_defined = true;
    prop_desc.is_enumerable = false;

    prop_desc.is_configurable_defined = true;
    prop_desc.is_configurable = true;
  }

  ecma_string_t *magic_string_constructor_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR);
  ecma_op_object_define_own_property (proto_p,
                                      magic_string_constructor_p,
                                      &prop_desc,
                                      false);
  ecma_deref_ecma_string (magic_string_constructor_p);

  // 18.
  prop_desc.value = ecma_make_object_value (proto_p);
  prop_desc.is_configurable = false;
  ecma_string_t *magic_string_prototype_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE);
  ecma_op_object_define_own_property (f,
                                      magic_string_prototype_p,
                                      &prop_desc,
                                      false);
  ecma_deref_ecma_string (magic_string_prototype_p);

  ecma_deref_object (proto_p);

  // 19.
  if (is_strict)
  {
    ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);

    prop_desc = ecma_make_empty_property_descriptor ();
    {
      prop_desc.is_enumerable_defined = true;
      prop_desc.is_enumerable = false;

      prop_desc.is_configurable_defined = true;
      prop_desc.is_configurable = false;

      prop_desc.is_get_defined = true;
      prop_desc.get_p = thrower_p;

      prop_desc.is_set_defined = true;
      prop_desc.set_p = thrower_p;
    }

    ecma_string_t *magic_string_caller_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER);
    ecma_op_object_define_own_property (f,
                                        magic_string_caller_p,
                                        &prop_desc,
                                        false);
    ecma_deref_ecma_string (magic_string_caller_p);

    ecma_string_t *magic_string_arguments_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
    ecma_op_object_define_own_property (f,
                                        magic_string_arguments_p,
                                        &prop_desc,
                                        false);
    ecma_deref_ecma_string (magic_string_arguments_p);

    ecma_deref_object (thrower_p);
  }

  return f;
} /* ecma_op_create_function_object */
/**
 * The JSON object's 'stringify' routine
 *
 * 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_stringify (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */
                             ecma_value_t arg1,  /**< value */
                             ecma_value_t arg2,  /**< replacer */
                             ecma_value_t arg3)  /**< space */
{
  ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  ecma_json_stringify_context_t context;

  /* 1. */
  context.occurence_stack_p = ecma_new_values_collection (NULL, 0, false);

  /* 2. */
  context.indent_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);

  /* 3. */
  context.property_list_p = ecma_new_values_collection (NULL, 0, false);

  context.replacer_function_p = NULL;

  /* 4. */
  if (ecma_is_value_object (arg2))
  {
    ecma_object_t *obj_p = ecma_get_object_from_value (arg2);

    /* 4.a */
    if (ecma_op_is_callable (arg2))
    {
      context.replacer_function_p = obj_p;
    }
    /* 4.b */
    else if (ecma_object_get_class_name (obj_p) == LIT_MAGIC_STRING_ARRAY_UL)
    {
      ecma_string_t *length_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);

      ECMA_TRY_CATCH (array_length,
                      ecma_op_object_get (obj_p, length_str_p),
                      ret_value);

      ECMA_OP_TO_NUMBER_TRY_CATCH (array_length_num,
                                   array_length,
                                   ret_value);

      uint32_t array_length = ecma_number_to_uint32 (array_length_num);
      uint32_t index = 0;

      /* 4.b.ii */
      while ((index < array_length) && ecma_is_value_empty (ret_value))
      {
        ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index);

        ECMA_TRY_CATCH (value,
                        ecma_op_object_get (obj_p, index_str_p),
                        ret_value);

        /* 4.b.ii.1 */
        ecma_value_t item = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);

        /* 4.b.ii.2 */
        if (ecma_is_value_string (value))
        {
          item = ecma_copy_value (value, true);
        }
        /* 4.b.ii.3 */
        else if (ecma_is_value_number (value))
        {
          ECMA_TRY_CATCH (str_val,
                          ecma_op_to_string (value),
                          ret_value);

          item = ecma_copy_value (str_val, true);

          ECMA_FINALIZE (str_val);
        }
        /* 4.b.ii.4 */
        else if (ecma_is_value_object (value))
        {
          ecma_object_t *obj_val_p = ecma_get_object_from_value (value);
          lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_val_p);

          /* 4.b.ii.4.a */
          if (class_name == LIT_MAGIC_STRING_NUMBER_UL
              || class_name == LIT_MAGIC_STRING_STRING_UL)
          {
            ECMA_TRY_CATCH (val,
                            ecma_op_to_string (value),
                            ret_value);

            item = ecma_copy_value (val, true);

            ECMA_FINALIZE (val);
          }
        }

        /* 4.b.ii.5 */
        if (!ecma_is_value_undefined (item))
        {
          if (!ecma_has_string_value_in_collection (context.property_list_p, item))
          {
            ecma_append_to_values_collection (context.property_list_p, item, true);
            ecma_deref_ecma_string (ecma_get_string_from_value (item));
          }
          else
          {
            ecma_free_value (item);
          }
        }

        ECMA_FINALIZE (value);

        ecma_deref_ecma_string (index_str_p);

        index++;
      }

      ECMA_OP_TO_NUMBER_FINALIZE (array_length_num);
      ECMA_FINALIZE (array_length);

      ecma_deref_ecma_string (length_str_p);
    }
  }

  if (ecma_is_value_empty (ret_value))
  {
    ecma_value_t space = ecma_copy_value (arg3, true);

    /* 5. */
    if (ecma_is_value_object (arg3))
    {
      ecma_object_t *obj_p = ecma_get_object_from_value (arg3);
      lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_p);

      /* 5.a */
      if (class_name == LIT_MAGIC_STRING_NUMBER_UL)
      {
        ECMA_TRY_CATCH (val,
                        ecma_op_to_number (arg3),
                        ret_value);

        ecma_free_value (space);
        space = ecma_copy_value (val, true);

        ECMA_FINALIZE (val);
      }
      /* 5.b */
      else if (class_name == LIT_MAGIC_STRING_STRING_UL)
      {
        ECMA_TRY_CATCH (val,
                        ecma_op_to_string (arg3),
                        ret_value);

        ecma_free_value (space);
        space = ecma_copy_value (val, true);

        ECMA_FINALIZE (val);
      }
    }

    if (ecma_is_value_empty (ret_value))
    {
      /* 6. */
      if (ecma_is_value_number (space))
      {
        ECMA_OP_TO_NUMBER_TRY_CATCH (array_length_num,
                                     arg3,
                                     ret_value);

        /* 6.a */
        int32_t num_of_spaces = ecma_number_to_int32 (array_length_num);
        int32_t space = (num_of_spaces > 10) ? 10 : num_of_spaces;

        /* 6.b */
        if (space < 1)
        {
          context.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
        }
        else
        {
          MEM_DEFINE_LOCAL_ARRAY (space_buff, space, char);

          for (int32_t i = 0; i < space; i++)
          {
            space_buff[i] = LIT_CHAR_SP;
          }

          context.gap_str_p = ecma_new_ecma_string_from_utf8 ((lit_utf8_byte_t *) space_buff, (lit_utf8_size_t) space);

          MEM_FINALIZE_LOCAL_ARRAY (space_buff);
        }

        ECMA_OP_TO_NUMBER_FINALIZE (array_length_num);
      }
      /* 7. */
      else if (ecma_is_value_string (space))
      {
        ecma_string_t *space_str_p = ecma_get_string_from_value (space);
        ecma_length_t num_of_chars = ecma_string_get_length (space_str_p);

        if (num_of_chars < 10)
        {
          context.gap_str_p = ecma_copy_or_ref_ecma_string (space_str_p);
        }
        else
        {
          context.gap_str_p = ecma_string_substr (space_str_p, 0, 10);
        }
      }
      /* 8. */
      else
      {
        context.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
      }
    }

    ecma_free_value (space);

    if (ecma_is_value_empty (ret_value))
    {
      /* 9. */
      ecma_object_t *obj_wrapper_p = ecma_op_create_object_object_noarg ();
      ecma_string_t *empty_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);

      /* 10. */
      ecma_value_t put_comp_val = ecma_op_object_put (obj_wrapper_p,
                                                      empty_str_p,
                                                      arg1,
                                                      false);

      JERRY_ASSERT (ecma_is_value_true (put_comp_val));
      ecma_free_value (put_comp_val);

      /* 11. */
      ECMA_TRY_CATCH (str_val,
                      ecma_builtin_json_str (empty_str_p, obj_wrapper_p, &context),
                      ret_value);

      ret_value = ecma_copy_value (str_val, true);

      ECMA_FINALIZE (str_val);

      ecma_deref_object (obj_wrapper_p);
      ecma_deref_ecma_string (empty_str_p);
    }

    ecma_deref_ecma_string (context.gap_str_p);
  }

  ecma_deref_ecma_string (context.indent_str_p);

  ecma_free_values_collection (context.property_list_p, true);
  ecma_free_values_collection (context.occurence_stack_p, true);

  return ret_value;
} /* ecma_builtin_json_stringify */
/**
 * 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 */
/**
 * Parse next value.
 *
 * The function fills the fields of the ecma_json_token_t
 * argument and advances the string pointer.
 *
 * @return ecma_value with the property value
 */
static ecma_value_t
ecma_builtin_json_parse_value (ecma_json_token_t *token_p) /**< token argument */
{
  ecma_builtin_json_parse_next_token (token_p);

  switch (token_p->type)
  {
    case number_token:
    {
      ecma_number_t *number_p = ecma_alloc_number ();
      *number_p = token_p->u.number;
      return ecma_make_number_value (number_p);
    }
    case string_token:
    {
      ecma_string_t *string_p = ecma_new_ecma_string_from_utf8 (token_p->u.string.start_p, token_p->u.string.size);
      return ecma_make_string_value (string_p);
    }
    case null_token:
    {
      return ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL);
    }
    case true_token:
    {
      return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
    }
    case false_token:
    {
      return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE);
    }
    case left_brace_token:
    {
      bool parse_comma = false;
      ecma_object_t *object_p = ecma_op_create_object_object_noarg ();

      while (true)
      {
        ecma_builtin_json_parse_next_token (token_p);

        if (token_p->type == right_brace_token)
        {
          return ecma_make_object_value (object_p);
        }

        if (parse_comma)
        {
          if (token_p->type != comma_token)
          {
            break;
          }
          ecma_builtin_json_parse_next_token (token_p);
        }

        if (token_p->type != string_token)
        {
          break;
        }

        lit_utf8_byte_t *string_start_p = token_p->u.string.start_p;
        lit_utf8_size_t string_size = token_p->u.string.size;
        ecma_builtin_json_parse_next_token (token_p);

        if (token_p->type != colon_token)
        {
          break;
        }

        ecma_value_t value = ecma_builtin_json_parse_value (token_p);

        if (ecma_is_value_undefined (value))
        {
          break;
        }

        ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (string_start_p, string_size);
        ecma_builtin_json_define_value_property (object_p, name_p, value);
        ecma_deref_ecma_string (name_p);
        ecma_free_value (value);
        parse_comma = true;
      }

      /*
       * Parse error occured.
       */
      ecma_deref_object (object_p);
      return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
    }
    case left_square_token:
    {
      bool parse_comma = false;
      uint32_t length = 0;

      ecma_value_t array_construction = ecma_op_create_array_object (NULL, 0, false);
      JERRY_ASSERT (!ecma_is_value_error (array_construction));

      ecma_object_t *array_p = ecma_get_object_from_value (array_construction);

      while (true)
      {
        if (ecma_builtin_json_check_right_square_token (token_p))
        {
          return ecma_make_object_value (array_p);
        }

        if (parse_comma)
        {
          ecma_builtin_json_parse_next_token (token_p);
          if (token_p->type != comma_token)
          {
            break;
          }
        }

        ecma_value_t value = ecma_builtin_json_parse_value (token_p);

        if (ecma_is_value_undefined (value))
        {
          break;
        }

        ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (length);

        ecma_value_t completion = ecma_builtin_helper_def_prop (array_p,
                                                                index_str_p,
                                                                value,
                                                                true, /* Writable */
                                                                true, /* Enumerable */
                                                                true, /* Configurable */
                                                                false); /* Failure handling */

        JERRY_ASSERT (ecma_is_value_true (completion));

        ecma_deref_ecma_string (index_str_p);

        ecma_free_value (value);

        length++;
        parse_comma = true;
      }

      /*
       * Parse error occured.
       */
      ecma_deref_object (array_p);
      return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
    }
    default:
    {
      return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
    }
  }
} /* ecma_builtin_json_parse_value */