/**
 * [[GetProperty]] ecma general object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 8.12.2
 *
 * @return pointer to a property - if it exists,
 *         NULL (i.e. ecma-undefined) - otherwise.
 */
ecma_property_t*
ecma_op_general_object_get_property (ecma_object_t *obj_p, /**< the object */
                                     ecma_string_t *property_name_p) /**< property name */
{
  JERRY_ASSERT (obj_p != NULL
                && !ecma_is_lexical_environment (obj_p));
  JERRY_ASSERT (property_name_p != NULL);

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

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

  // 3.
  ecma_object_t *prototype_p = ecma_get_object_prototype (obj_p);

  // 4., 5.
  if (prototype_p != NULL)
  {
    return ecma_op_object_get_property (prototype_p, property_name_p);
  }
  else
  {
    return NULL;
  }
} /* ecma_op_general_object_get_property */
/**
 * [[GetOwnProperty]] ecma Arguments object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 10.6
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value
 */
ecma_property_t *
ecma_op_arguments_object_get_own_property (ecma_object_t *obj_p, /**< the object */
                                           ecma_string_t *property_name_p) /**< property name */
{
  // 1.
  ecma_property_t *desc_p = ecma_op_general_object_get_own_property (obj_p, property_name_p);

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

  // 3.
  ecma_property_t *map_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP);
  ecma_object_t *map_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
                                                          ECMA_PROPERTY_VALUE_PTR (map_prop_p)->value);

  // 4.
  ecma_property_t *mapped_prop_p = ecma_op_object_get_own_property (map_p, property_name_p);

  // 5.
  if (mapped_prop_p != NULL)
  {
    // a.
    ecma_value_t completion = ecma_arguments_get_mapped_arg_value (map_p, mapped_prop_p);

    ecma_named_data_property_assign_value (obj_p, desc_p, completion);

    ecma_free_value (completion);
  }

  // 6.
  return desc_p;
} /* ecma_op_arguments_object_get_own_property */
/**
 * [[Get]] ecma Arguments object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 10.6
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value
 */
ecma_value_t
ecma_op_arguments_object_get (ecma_object_t *obj_p, /**< the object */
                              ecma_string_t *property_name_p) /**< property name */
{
  // 1.
  ecma_property_t *map_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP);
  ecma_object_t *map_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
                                                          ECMA_PROPERTY_VALUE_PTR (map_prop_p)->value);

  // 2.
  ecma_property_t *mapped_prop_p = ecma_op_object_get_own_property (map_p, property_name_p);

  // 3.
  if (mapped_prop_p == NULL)
  {
    /* We don't check for 'caller' (item 3.b) here, because the 'caller' property is defined
       as non-configurable and it's get/set are set to [[ThrowTypeError]] object */

    return ecma_op_general_object_get (obj_p, property_name_p);
  }
  else
  {
    // 4.
    return ecma_arguments_get_mapped_arg_value (map_p, mapped_prop_p);
  }
} /* ecma_op_arguments_object_get */
/**
 * The Object object's 'isSealed' routine
 *
 * See also:
 *          ECMA-262 v5, 15.2.3.11
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_object_object_is_sealed (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */
                                      ecma_value_t arg) /**< routine's argument */
{
  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

  // 1.
  if (!ecma_is_value_object (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 (arg);

    bool is_sealed;

    // 3.
    if (ecma_get_object_extensible (obj_p))
    {
      is_sealed = false;
    }
    else
    {
      /* the value can be updated in the loop below */
      is_sealed = true;

      // 2.
      ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false);

      ecma_collection_iterator_t iter;
      ecma_collection_iterator_init (&iter, props_p);

      while (ecma_collection_iterator_next (&iter))
      {
        ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p);

        // 2.a
        ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p);

        // 2.b
        if (ecma_is_property_configurable (property_p))
        {
          is_sealed = false;
          break;
        }
      }

      ecma_free_values_collection (props_p, true);
    }

    // 4.
    ret_value = ecma_make_simple_completion_value (is_sealed
                                                   ? ECMA_SIMPLE_VALUE_TRUE
                                                   : ECMA_SIMPLE_VALUE_FALSE);
  }

  return ret_value;
} /* ecma_builtin_object_object_is_sealed */
/**
 * The Object object's 'getOwnPropertyDescriptor' routine
 *
 * See also:
 *          ECMA-262 v5, 15.2.3.3
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_object_object_get_own_property_descriptor (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));
    return ret_value;
  }

  ecma_object_t *obj_p = ecma_get_object_from_value (arg1);

  // 2.
  ECMA_TRY_CATCH (name_str_value,
                  ecma_op_to_string (arg2),
                  ret_value);

  ecma_string_t *name_str_p = ecma_get_string_from_value (name_str_value);

  // 3.
  ecma_property_t *prop_p = ecma_op_object_get_own_property (obj_p, name_str_p);

  if (prop_p != NULL)
  {
    ecma_property_descriptor_t prop_desc = ecma_get_property_descriptor_from_property (prop_p);

    // 4.
    ecma_object_t* desc_obj_p = ecma_op_from_property_descriptor (&prop_desc);

    ecma_free_property_descriptor (&prop_desc);

    ret_value = ecma_make_normal_completion_value (ecma_make_object_value (desc_obj_p));
  }
  else
  {
    ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED);
  }

  ECMA_FINALIZE (name_str_value);

  return ret_value;
} /* ecma_builtin_object_object_get_own_property_descriptor */
/**
 * The Object.prototype object's 'propertyIsEnumerable' routine
 *
 * See also:
 *          ECMA-262 v5, 15.2.4.7
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
 */
static ecma_value_t
ecma_builtin_object_prototype_object_property_is_enumerable (ecma_value_t this_arg, /**< this argument */
                                                             ecma_value_t arg) /**< routine's first argument */
{
  ecma_value_t return_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  /* 1. */
  ECMA_TRY_CATCH (to_string_val,
                  ecma_op_to_string (arg),
                  return_value);

  /* 2. */
  ECMA_TRY_CATCH (obj_val,
                  ecma_op_to_object (this_arg),
                  return_value);

  ecma_string_t *property_name_string_p = ecma_get_string_from_value (to_string_val);

  ecma_object_t *obj_p = ecma_get_object_from_value (obj_val);

  /* 3. */
  ecma_property_t property = ecma_op_object_get_own_property (obj_p,
                                                              property_name_string_p,
                                                              NULL,
                                                              ECMA_PROPERTY_GET_NO_OPTIONS);

  /* 4. */
  if (property != ECMA_PROPERTY_TYPE_NOT_FOUND)
  {
    bool is_enumerable = ecma_is_property_enumerable (property);

    return_value = ecma_make_boolean_value (is_enumerable);
  }
  else
  {
    return_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE);
  }

  ECMA_FINALIZE (obj_val);

  ECMA_FINALIZE (to_string_val);

  return return_value;
} /* ecma_builtin_object_prototype_object_property_is_enumerable */
/**
 * [[Delete]] ecma Arguments object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 10.6
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value
 */
ecma_value_t
ecma_op_arguments_object_delete (ecma_object_t *obj_p, /**< the object */
                                 ecma_string_t *property_name_p, /**< property name */
                                 bool is_throw) /**< flag that controls failure handling */
{
  // 1.
  ecma_property_t *map_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP);
  ecma_object_t *map_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t,
                                                    map_prop_p->u.internal_property.value);

  // 2.
  ecma_property_t *mapped_prop_p = ecma_op_object_get_own_property (map_p, property_name_p);

  // 3.
  ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  ECMA_TRY_CATCH (delete_in_args_ret,
                  ecma_op_general_object_delete (obj_p,
                                                 property_name_p,
                                                 is_throw),
                  ret_value);

  if (ecma_is_value_true (delete_in_args_ret))
  {
    if (mapped_prop_p != NULL)
    {
      ecma_value_t delete_in_map_completion = ecma_op_object_delete (map_p, property_name_p, false);
      JERRY_ASSERT (ecma_is_value_true (delete_in_map_completion));
    }

    ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
  }
  else
  {
    JERRY_ASSERT (ecma_is_value_boolean (delete_in_args_ret));

    ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE);
  }

  ECMA_FINALIZE (delete_in_args_ret);

  return ret_value;
} /* ecma_op_arguments_object_delete */
/**
 * The Object.prototype object's 'propertyIsEnumerable' routine
 *
 * See also:
 *          ECMA-262 v5, 15.2.4.7
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_object_prototype_object_property_is_enumerable (ecma_value_t this_arg, /**< this argument */
                                                             ecma_value_t arg) /**< routine's first argument */
{
  ecma_completion_value_t return_value = ecma_make_empty_completion_value ();

  /* 1. */
  ECMA_TRY_CATCH (to_string_val,
                  ecma_op_to_string (arg),
                  return_value);

  /* 2. */
  ECMA_TRY_CATCH (obj_val,
                  ecma_op_to_object (this_arg),
                  return_value);

  ecma_string_t *property_name_string_p = ecma_get_string_from_value (to_string_val);

  ecma_object_t *obj_p = ecma_get_object_from_value (obj_val);

  /* 3. */
  ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_string_p);

  /* 4. */
  if (property_p != NULL)
  {
    bool is_enumerable = ecma_is_property_enumerable (property_p);

    return_value = ecma_make_simple_completion_value (is_enumerable
                                                      ? ECMA_SIMPLE_VALUE_TRUE
                                                      : ECMA_SIMPLE_VALUE_FALSE);
  }
  else
  {
    return_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE);
  }

  ECMA_FINALIZE (obj_val);

  ECMA_FINALIZE (to_string_val);

  return return_value;
} /* ecma_builtin_object_prototype_object_property_is_enumerable */
/**
 * [[Delete]] ecma general object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 8.12.7
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value
 */
ecma_completion_value_t
ecma_op_general_object_delete (ecma_object_t *obj_p, /**< the object */
                               ecma_string_t *property_name_p, /**< property name */
                               bool is_throw) /**< flag that controls failure handling */
{
  JERRY_ASSERT (obj_p != NULL
                && !ecma_is_lexical_environment (obj_p));
  JERRY_ASSERT (property_name_p != NULL);

  // 1.
  ecma_property_t *desc_p = ecma_op_object_get_own_property (obj_p, property_name_p);

  // 2.
  if (desc_p == NULL)
  {
    return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE);
  }

  // 3.
  if (ecma_is_property_configurable (desc_p))
  {
    // a.
    ecma_delete_property (obj_p, desc_p);

    // b.
    return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE);
  }
  else if (is_throw)
  {
    // 4.
    return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
  }
  else
  {
    // 5.
    return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE);
  }

  JERRY_UNREACHABLE ();
} /* ecma_op_general_object_delete */
/**
 * The Object.prototype object's 'hasOwnProperty' routine
 *
 * See also:
 *          ECMA-262 v5, 15.2.4.5
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
 */
static ecma_value_t
ecma_builtin_object_prototype_object_has_own_property (ecma_value_t this_arg, /**< this argument */
                                                       ecma_value_t arg) /**< first argument */
{
  ecma_value_t return_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  /* 1. */
  ECMA_TRY_CATCH (to_string_val,
                  ecma_op_to_string (arg),
                  return_value);

  /* 2. */
  ECMA_TRY_CATCH (obj_val,
                  ecma_op_to_object (this_arg),
                  return_value);

  ecma_string_t *property_name_string_p = ecma_get_string_from_value (to_string_val);

  ecma_object_t *obj_p = ecma_get_object_from_value (obj_val);

  /* 3. */
  ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_string_p);

  if (property_p != NULL)
  {
    return_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
  }
  else
  {
    return_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE);
  }
  ECMA_FINALIZE (obj_val);

  ECMA_FINALIZE (to_string_val);

  return return_value;
} /* ecma_builtin_object_prototype_object_has_own_property */
/**
 * The Object object's 'freeze' routine
 *
 * See also:
 *          ECMA-262 v5, 15.2.3.9
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_object_object_freeze (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */
                                   ecma_value_t arg) /**< routine's argument */
{
  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

  // 1.
  if (!ecma_is_value_object (arg))
  {
    ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
  }
  else
  {
    // 2.
    ecma_object_t *obj_p = ecma_get_object_from_value (arg);

    ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false);


    ecma_collection_iterator_t iter;
    ecma_collection_iterator_init (&iter, props_p);

    while (ecma_collection_iterator_next (&iter)
           && ecma_is_completion_value_empty (ret_value))
    {
      ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p);
      ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p);

      // 2.a
      ecma_property_descriptor_t prop_desc = ecma_get_property_descriptor_from_property (property_p);

      // 2.b
      if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_writable (property_p))
      {
        prop_desc.is_writable = false;
      }

      // 2.c
      if (ecma_is_property_configurable (property_p))
      {
        prop_desc.is_configurable = false;
      }

      // 2.d
      ECMA_TRY_CATCH (define_own_prop_ret,
                      ecma_op_object_define_own_property (obj_p,
                                                          property_name_p,
                                                          &prop_desc,
                                                          true),
                      ret_value);
      ECMA_FINALIZE (define_own_prop_ret);

      ecma_free_property_descriptor (&prop_desc);
    }

    ecma_free_values_collection (props_p, true);

    if (ecma_is_completion_value_empty (ret_value))
    {
      // 3.
      ecma_set_object_extensible (obj_p, false);

      // 4.
      ret_value = ecma_make_normal_completion_value (ecma_copy_value (arg, true));
    }
  }

  return ret_value;
} /* ecma_builtin_object_object_freeze */
/**
 * [[DefineOwnProperty]] ecma general object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 8.12.9
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value
 */
ecma_completion_value_t
ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the 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 (obj_p != NULL
                && !ecma_is_lexical_environment (obj_p));
  JERRY_ASSERT (property_name_p != NULL);

  const bool is_property_desc_generic_descriptor = (!property_desc_p->is_value_defined
                                                    && !property_desc_p->is_writable_defined
                                                    && !property_desc_p->is_get_defined
                                                    && !property_desc_p->is_set_defined);
  const bool is_property_desc_data_descriptor = (property_desc_p->is_value_defined
                                                 || property_desc_p->is_writable_defined);
  const bool is_property_desc_accessor_descriptor = (property_desc_p->is_get_defined
                                                     || property_desc_p->is_set_defined);

  // 1.
  ecma_property_t *current_p = ecma_op_object_get_own_property (obj_p, property_name_p);

  // 2.
  bool extensible = ecma_get_object_extensible (obj_p);

  if (current_p == NULL)
  {
    // 3.
    if (!extensible)
    {
      return ecma_reject (is_throw);
    }

    // 4.

    // a.
    if (is_property_desc_generic_descriptor
        || is_property_desc_data_descriptor)
    {
      ecma_property_t *new_prop_p = ecma_create_named_data_property (obj_p,
                                                                     property_name_p,
                                                                     property_desc_p->is_writable,
                                                                     property_desc_p->is_enumerable,
                                                                     property_desc_p->is_configurable);

      ecma_named_data_property_assign_value (obj_p, new_prop_p, property_desc_p->value);
    }
    else
    {
      // b.
      JERRY_ASSERT (is_property_desc_accessor_descriptor);

      ecma_create_named_accessor_property (obj_p,
                                           property_name_p,
                                           property_desc_p->get_p,
                                           property_desc_p->set_p,
                                           property_desc_p->is_enumerable,
                                           property_desc_p->is_configurable);

    }

    return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE);
  }

  // 5.
  if (is_property_desc_generic_descriptor
      && !property_desc_p->is_enumerable_defined
      && !property_desc_p->is_configurable_defined)
  {
    return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE);
  }

  // 6.
  const bool is_current_data_descriptor = (current_p->type == ECMA_PROPERTY_NAMEDDATA);
  const bool is_current_accessor_descriptor = (current_p->type == ECMA_PROPERTY_NAMEDACCESSOR);

  JERRY_ASSERT (is_current_data_descriptor || is_current_accessor_descriptor);

  bool is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = true;
  if (property_desc_p->is_value_defined)
  {
    if (!is_current_data_descriptor
        || !ecma_op_same_value (property_desc_p->value,
                                ecma_get_named_data_property_value (current_p)))
    {
      is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false;
    }
  }

  if (property_desc_p->is_writable_defined)
  {
    if (!is_current_data_descriptor
        || property_desc_p->is_writable != ecma_is_property_writable (current_p))
    {
      is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false;
    }
  }

  if (property_desc_p->is_get_defined)
  {
    if (!is_current_accessor_descriptor
        || property_desc_p->get_p != ecma_get_named_accessor_property_getter (current_p))
    {
      is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false;
    }
  }

  if (property_desc_p->is_set_defined)
  {
    if (!is_current_accessor_descriptor
        || property_desc_p->set_p != ecma_get_named_accessor_property_setter (current_p))
    {
      is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false;
    }
  }

  if (property_desc_p->is_enumerable_defined)
  {
    if (property_desc_p->is_enumerable != ecma_is_property_enumerable (current_p))
    {
      is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false;
    }
  }

  if (property_desc_p->is_configurable_defined)
  {
    if (property_desc_p->is_configurable != ecma_is_property_configurable (current_p))
    {
      is_every_field_in_desc_also_occurs_in_current_desc_with_same_value = false;
    }
  }

  if (is_every_field_in_desc_also_occurs_in_current_desc_with_same_value)
  {
    return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE);
  }

  // 7.
  if (!ecma_is_property_configurable (current_p))
  {
    if (property_desc_p->is_configurable
        || (property_desc_p->is_enumerable_defined
            && property_desc_p->is_enumerable != ecma_is_property_enumerable (current_p)))
    {
      // a., b.
      return ecma_reject (is_throw);
    }
  }

  // 8.
  if (is_property_desc_generic_descriptor)
  {
    // no action required
  }
  else if (is_property_desc_data_descriptor != is_current_data_descriptor)
  {
    // 9.
    if (!ecma_is_property_configurable (current_p))
    {
      // a.
      return ecma_reject (is_throw);
    }

    bool was_enumerable = ecma_is_property_enumerable (current_p);
    bool was_configurable = ecma_is_property_configurable (current_p);

    ecma_delete_property (obj_p, current_p);

    if (is_current_data_descriptor)
    {
      // b.

      current_p = ecma_create_named_accessor_property (obj_p,
                                                       property_name_p,
                                                       NULL,
                                                       NULL,
                                                       was_enumerable,
                                                       was_configurable);
    }
    else
    {
      // c.

      current_p = ecma_create_named_data_property (obj_p,
                                                   property_name_p,
                                                   false,
                                                   was_enumerable,
                                                   was_configurable);
    }
  }
  else if (is_property_desc_data_descriptor && is_current_data_descriptor)
  {
    // 10.
    if (!ecma_is_property_configurable (current_p))
    {
      // a.
      if (!ecma_is_property_writable (current_p))
      {
        // i.
        if (property_desc_p->is_writable)
        {
          return ecma_reject (is_throw);
        }

        // ii.
        if (property_desc_p->is_value_defined
            && !ecma_op_same_value (property_desc_p->value,
                                    ecma_get_named_data_property_value (current_p)))
        {
          return ecma_reject (is_throw);
        }
      }
    }
  }
  else
  {
    JERRY_ASSERT (is_property_desc_accessor_descriptor && is_current_accessor_descriptor);

    // 11.

    if (!ecma_is_property_configurable (current_p))
    {
      // a.

      if ((property_desc_p->is_get_defined
           && property_desc_p->get_p != ecma_get_named_accessor_property_getter (current_p))
          || (property_desc_p->is_set_defined
              && property_desc_p->set_p != ecma_get_named_accessor_property_setter (current_p)))
      {
        // i., ii.
        return ecma_reject (is_throw);
      }
    }
  }

  // 12.
  if (property_desc_p->is_value_defined)
  {
    JERRY_ASSERT (current_p->type == ECMA_PROPERTY_NAMEDDATA);

    ecma_named_data_property_assign_value (obj_p, current_p, property_desc_p->value);
  }

  if (property_desc_p->is_writable_defined)
  {
    JERRY_ASSERT (current_p->type == ECMA_PROPERTY_NAMEDDATA);

    ecma_set_property_writable_attr (current_p, property_desc_p->is_writable);
  }

  if (property_desc_p->is_get_defined)
  {
    JERRY_ASSERT (current_p->type == ECMA_PROPERTY_NAMEDACCESSOR);

    ecma_set_named_accessor_property_getter (obj_p, current_p, property_desc_p->get_p);
  }

  if (property_desc_p->is_set_defined)
  {
    JERRY_ASSERT (current_p->type == ECMA_PROPERTY_NAMEDACCESSOR);

    ecma_set_named_accessor_property_setter (obj_p, current_p, property_desc_p->set_p);
  }

  if (property_desc_p->is_enumerable_defined)
  {
    ecma_set_property_enumerable_attr (current_p, property_desc_p->is_enumerable);
  }

  if (property_desc_p->is_configurable_defined)
  {
    ecma_set_property_configurable_attr (current_p, property_desc_p->is_configurable);
  }

  return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE);
} /* ecma_op_general_object_define_own_property */
/**
 * [[CanPut]] ecma general object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 8.12.4
 *
 * @return true - if [[Put]] with the given property name can be performed;
 *         false - otherwise.
 */
bool
ecma_op_general_object_can_put (ecma_object_t *obj_p, /**< the object */
                                ecma_string_t *property_name_p) /**< property name */
{
  JERRY_ASSERT (obj_p != NULL
                && !ecma_is_lexical_environment (obj_p));
  JERRY_ASSERT (property_name_p != NULL);

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

  // 2.
  if (prop_p != NULL)
  {
    // a.
    if (prop_p->type == ECMA_PROPERTY_NAMEDACCESSOR)
    {
      ecma_object_t *setter_p = ecma_get_named_accessor_property_setter (prop_p);

      // i.
      if (setter_p == NULL)
      {
        return false;
      }

      // ii.
      return true;
    }
    else
    {
      // b.

      JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA);

      return ecma_is_property_writable (prop_p);
    }
  }

  // 3.
  ecma_object_t *proto_p = ecma_get_object_prototype (obj_p);

  // 4.
  if (proto_p == NULL)
  {
    return ecma_get_object_extensible (obj_p);
  }

  // 5.
  ecma_property_t *inherited_p = ecma_op_object_get_property (proto_p, property_name_p);

  // 6.
  if (inherited_p == NULL)
  {
    return ecma_get_object_extensible (obj_p);
  }

  // 7.
  if (inherited_p->type == ECMA_PROPERTY_NAMEDACCESSOR)
  {
    ecma_object_t *setter_p = ecma_get_named_accessor_property_setter (inherited_p);

    // a.
    if (setter_p == NULL)
    {
      return false;
    }

    // b.
    return true;
  }
  else
  {
    // 8.
    JERRY_ASSERT (inherited_p->type == ECMA_PROPERTY_NAMEDDATA);

    // a.
    if (!ecma_get_object_extensible (obj_p))
    {
      return false;
    }
    else
    {
      // b.
      return ecma_is_property_writable (inherited_p);
    }
  }

  JERRY_UNREACHABLE ();
} /* ecma_op_general_object_can_put */
/**
 * [[Put]] ecma general object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 8.12.5
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value
 */
ecma_completion_value_t
ecma_op_general_object_put (ecma_object_t *obj_p, /**< the object */
                            ecma_string_t *property_name_p, /**< property name */
                            ecma_value_t value, /**< ecma-value */
                            bool is_throw) /**< flag that controls failure handling */
{
  JERRY_ASSERT (obj_p != NULL
                && !ecma_is_lexical_environment (obj_p));
  JERRY_ASSERT (property_name_p != NULL);

  // 1.
  if (!ecma_op_object_can_put (obj_p, property_name_p))
  {
    if (is_throw)
    {
      // a.
      return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
    }
    else
    {
      // b.
      return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE);
    }
  }

  // 2.
  ecma_property_t *own_desc_p = ecma_op_object_get_own_property (obj_p, property_name_p);

  // 3.
  if (own_desc_p != NULL
      && own_desc_p->type == ECMA_PROPERTY_NAMEDDATA)
  {
    // a.
    ecma_property_descriptor_t value_desc = ecma_make_empty_property_descriptor ();
    {
      value_desc.is_value_defined = true;
      value_desc.value = value;
    }

    // b., c.
    return ecma_op_object_define_own_property (obj_p,
                                               property_name_p,
                                               &value_desc,
                                               is_throw);
  }

  // 4.
  ecma_property_t *desc_p = ecma_op_object_get_property (obj_p, property_name_p);

  // 5.
  if (desc_p != NULL
      && desc_p->type == ECMA_PROPERTY_NAMEDACCESSOR)
  {
    // a.
    ecma_object_t *setter_p = ecma_get_named_accessor_property_setter (desc_p);
    JERRY_ASSERT (setter_p != NULL);

    ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

    ECMA_TRY_CATCH (call_ret,
                    ecma_op_function_call_array_args (setter_p,
                                                      ecma_make_object_value (obj_p),
                                                      &value,
                                                      1),
                    ret_value);

    ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE);

    ECMA_FINALIZE (call_ret);

    return ret_value;
  }
  else
  {
    // 6.a., 6.b.
    return ecma_builtin_helper_def_prop (obj_p,
                                         property_name_p,
                                         value,
                                         true, /* Writable */
                                         true, /* Enumerable */
                                         true, /* Configurable */
                                         is_throw); /* Failure handling */
  }

  JERRY_UNREACHABLE ();
} /* ecma_op_general_object_put */
Example #15
0
/**
 * Abstract operation 'JO' 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_object (ecma_object_t *obj_p, /**< the object*/
                          ecma_json_stringify_context_t *context_p) /**< context*/
{
  ecma_value_t obj_value = ecma_make_object_value (obj_p);

  /* 1. */
  if (ecma_has_object_value_in_collection (context_p->occurence_stack_p, obj_value))
  {
    return ecma_raise_type_error ("");
  }

  ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  /* 2. */
  ecma_append_to_values_collection (context_p->occurence_stack_p, obj_value, true);

  /* 3. */
  ecma_string_t *stepback_p = context_p->indent_str_p;

  /* 4. */
  context_p->indent_str_p = ecma_concat_ecma_strings (context_p->indent_str_p, context_p->gap_str_p);

  ecma_collection_header_t *property_keys_p;

  /* 5. */
  if (context_p->property_list_p->unit_number > 0)
  {
    property_keys_p = context_p->property_list_p;
  }
  /* 6. */
  else
  {
    property_keys_p = ecma_new_values_collection (NULL, 0, true);

    ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, true, false);

    ecma_collection_iterator_t iter;
    ecma_collection_iterator_init (&iter, props_p);

    while (ecma_collection_iterator_next (&iter))
    {
      ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p);
      ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p);

      JERRY_ASSERT (ecma_is_property_enumerable (property_p));

      if (property_p->type == ECMA_PROPERTY_NAMEDDATA)
      {
        ecma_append_to_values_collection (property_keys_p, *iter.current_value_p, true);
      }
    }

    ecma_free_values_collection (props_p, true);
  }

  /* 7. */
  ecma_collection_header_t *partial_p = ecma_new_values_collection (NULL, 0, true);

  /* 8. */
  ecma_collection_iterator_t iterator;
  ecma_collection_iterator_init (&iterator, property_keys_p);

  while (ecma_collection_iterator_next (&iterator) && ecma_is_value_empty (ret_value))
  {
    ecma_value_t value = *iterator.current_value_p;
    ecma_string_t *key_p = ecma_get_string_from_value (value);

    /* 8.a */
    ECMA_TRY_CATCH (str_val,
                    ecma_builtin_json_str (key_p, obj_p, context_p),
                    ret_value);

    /* 8.b */
    if (!ecma_is_value_undefined (str_val))
    {
      ecma_string_t *colon_p = ecma_get_magic_string (LIT_MAGIC_STRING_COLON_CHAR);
      ecma_string_t *value_str_p = ecma_get_string_from_value (str_val);
      ecma_string_t *tmp_str_p;

      /* 8.b.i */
      ecma_value_t str_comp_val = ecma_builtin_json_quote (key_p);
      JERRY_ASSERT (!ecma_is_value_error (str_comp_val));

      ecma_string_t *member_str_p = ecma_get_string_from_value (str_comp_val);

      /* 8.b.ii */
      tmp_str_p = ecma_concat_ecma_strings (member_str_p, colon_p);
      ecma_free_value (str_comp_val);
      ecma_deref_ecma_string (colon_p);
      member_str_p = tmp_str_p;

      /* 8.b.iii */
      bool is_gap_empty = (ecma_string_get_length (context_p->gap_str_p) == 0);

      if (!is_gap_empty)
      {
        ecma_string_t *space_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_SPACE_CHAR);

        tmp_str_p = ecma_concat_ecma_strings (member_str_p, space_str_p);
        ecma_deref_ecma_string (member_str_p);
        ecma_deref_ecma_string (space_str_p);
        member_str_p = tmp_str_p;
      }

      /* 8.b.iv */
      tmp_str_p = ecma_concat_ecma_strings (member_str_p, value_str_p);
      ecma_deref_ecma_string (member_str_p);
      member_str_p = tmp_str_p;

      /* 8.b.v */
      ecma_value_t member_value = ecma_make_string_value (member_str_p);
      ecma_append_to_values_collection (partial_p, member_value, true);
      ecma_deref_ecma_string (member_str_p);
    }

    ECMA_FINALIZE (str_val);
  }

  if (context_p->property_list_p->unit_number == 0)
  {
    ecma_free_values_collection (property_keys_p, true);
  }

  if (!ecma_is_value_empty (ret_value))
  {
    ecma_free_values_collection (partial_p, true);
    ecma_deref_ecma_string (stepback_p);
    return ret_value;
  }

  /* 9. */
  if (partial_p->unit_number == 0)
  {
    ecma_string_t *left_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_BRACE_CHAR);
    ecma_string_t *right_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR);

    ecma_string_t *final_str_p = ecma_concat_ecma_strings (left_brace_str_p, right_brace_str_p);
    ret_value = ecma_make_string_value (final_str_p);

    ecma_deref_ecma_string (left_brace_str_p);
    ecma_deref_ecma_string (right_brace_str_p);
  }
  /* 10. */
  else
  {
    bool is_gap_empty = (ecma_string_get_length (context_p->gap_str_p) == 0);

    /* 10.a */
    if (is_gap_empty)
    {
      ecma_string_t *left_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_BRACE_CHAR);
      ecma_string_t *right_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR);

      ret_value = ecma_builtin_helper_json_create_non_formatted_json (left_brace_str_p,
                                                                      right_brace_str_p,
                                                                      partial_p);

      ecma_deref_ecma_string (left_brace_str_p);
      ecma_deref_ecma_string (right_brace_str_p);
    }
    /* 10.b */
    else
    {
      ecma_string_t *left_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_BRACE_CHAR);
      ecma_string_t *right_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR);

      ret_value = ecma_builtin_helper_json_create_formatted_json (left_brace_str_p,
                                                                  right_brace_str_p,
                                                                  stepback_p,
                                                                  partial_p,
                                                                  context_p);

      ecma_deref_ecma_string (left_brace_str_p);
      ecma_deref_ecma_string (right_brace_str_p);
    }
  }

  ecma_free_values_collection (partial_p, true);

  /* 11. */
  ecma_remove_last_value_from_values_collection (context_p->occurence_stack_p);

  /* 12. */
  ecma_deref_ecma_string (context_p->indent_str_p);
  context_p->indent_str_p = stepback_p;

  /* 13. */
  return ret_value;
} /* ecma_builtin_json_object */
Example #16
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);

                        bool reduce_succeeded = true;

                        while (new_len_uint32 < old_len_uint32)
                        {
                            // i
                            old_len_uint32--;

                            // ii
                            ecma_string_t *old_length_string_p = ecma_new_ecma_string_from_uint32 (old_len_uint32);
                            ecma_completion_value_t delete_succeeded = ecma_op_object_delete (obj_p,
                                    old_length_string_p,
                                    false);
                            ecma_deref_ecma_string (old_length_string_p);

                            // iii
                            if (ecma_is_completion_value_normal_false (delete_succeeded))
                            {
                                JERRY_ASSERT (ecma_is_value_number (new_len_property_desc.value));

                                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 (old_len_uint32 + 1);

                                // 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));

                                reduce_succeeded = false;

                                break;
                            }
                        }

                        if (!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 Object object's 'isFrozen' routine
 *
 * See also:
 *          ECMA-262 v5, 15.2.3.12
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_object_object_is_frozen (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */
                                      ecma_value_t arg) /**< routine's argument */
{
  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

  // 1.
  if (!ecma_is_value_object (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 (arg);

    bool is_frozen;

    // 3.
    if (ecma_get_object_extensible (obj_p))
    {
      is_frozen = false;
    }
    else
    {
      is_frozen = true;

      // 2.
      ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false);

      ecma_collection_iterator_t iter;
      ecma_collection_iterator_init (&iter, props_p);

      while (ecma_collection_iterator_next (&iter))
      {
        ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p);

        // 2.a
        ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p);

        JERRY_ASSERT (property_p->type == ECMA_PROPERTY_NAMEDDATA || property_p->type == ECMA_PROPERTY_NAMEDACCESSOR);

        // 2.b
        if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_writable (property_p))
        {
          is_frozen = false;
          break;
        }

        // 2.c
        if (ecma_is_property_configurable (property_p))
        {
          is_frozen = false;
          break;
        }
      }

      ecma_free_values_collection (props_p, true);
    }

    // 4.
    ret_value = ecma_make_simple_completion_value (is_frozen
                                                   ? ECMA_SIMPLE_VALUE_TRUE
                                                   : ECMA_SIMPLE_VALUE_FALSE);
  }

  return ret_value;
} /* ecma_builtin_object_object_is_frozen */
/**
 * [[DefineOwnProperty]] ecma general object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 8.12.9
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value
 */
ecma_value_t
ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the 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 (obj_p != NULL
                && !ecma_is_lexical_environment (obj_p));
  JERRY_ASSERT (property_name_p != NULL);

  ecma_property_types_t property_desc_type = ECMA_PROPERTY_TYPE_GENERIC;

  if (property_desc_p->is_value_defined
      || property_desc_p->is_writable_defined)
  {
    /* A property descriptor cannot be both named data and named accessor. */
    JERRY_ASSERT (!property_desc_p->is_get_defined
                  && !property_desc_p->is_set_defined);
    property_desc_type = ECMA_PROPERTY_TYPE_NAMEDDATA;
  }
  else if (property_desc_p->is_get_defined
           || property_desc_p->is_set_defined)
  {
    property_desc_type = ECMA_PROPERTY_TYPE_NAMEDACCESSOR;
  }

  /* These three asserts ensures that a new property is created with the appropriate default flags.
   * E.g. if is_configurable_defined is false, the newly created property must be non-configurable. */
  JERRY_ASSERT (property_desc_p->is_configurable_defined || !property_desc_p->is_configurable);
  JERRY_ASSERT (property_desc_p->is_enumerable_defined || !property_desc_p->is_enumerable);
  JERRY_ASSERT (property_desc_p->is_writable_defined || !property_desc_p->is_writable);

  // 1.
  ecma_property_t *current_p = ecma_op_object_get_own_property (obj_p, property_name_p);

  if (current_p == NULL)
  {
    // 3.
    if (!ecma_get_object_extensible (obj_p))
    {
      // 2.
      return ecma_reject (is_throw);
    }

    // 4.

    if (property_desc_type != ECMA_PROPERTY_TYPE_NAMEDACCESSOR)
    {
      // a.

      JERRY_ASSERT (property_desc_type == ECMA_PROPERTY_TYPE_GENERIC
                    || property_desc_type == ECMA_PROPERTY_TYPE_NAMEDDATA);

      ecma_property_t *new_prop_p = ecma_create_named_data_property (obj_p,
                                                                     property_name_p,
                                                                     property_desc_p->is_writable,
                                                                     property_desc_p->is_enumerable,
                                                                     property_desc_p->is_configurable);


      JERRY_ASSERT (property_desc_p->is_value_defined
                    || ecma_is_value_undefined (property_desc_p->value));

      ecma_named_data_property_assign_value (obj_p, new_prop_p, property_desc_p->value);
    }
    else
    {
      // b.

      ecma_create_named_accessor_property (obj_p,
                                           property_name_p,
                                           property_desc_p->get_p,
                                           property_desc_p->set_p,
                                           property_desc_p->is_enumerable,
                                           property_desc_p->is_configurable);
    }

    return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
  }

  // 6.
  ecma_property_types_t current_property_type = ECMA_PROPERTY_GET_TYPE (current_p);
  const bool is_current_configurable = ecma_is_property_configurable (current_p);

  JERRY_ASSERT (current_property_type == ECMA_PROPERTY_TYPE_NAMEDDATA
                || current_property_type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);

  // 7. a., b.
  if (!is_current_configurable
      && (property_desc_p->is_configurable
          || (property_desc_p->is_enumerable_defined
              && (property_desc_p->is_enumerable != ecma_is_property_enumerable (current_p)))))
  {
    return ecma_reject (is_throw);
  }

  // 8.
  if (property_desc_type == ECMA_PROPERTY_TYPE_GENERIC)
  {
    /* No action required. */
  }
  else if (likely (property_desc_type == current_property_type))
  {
    /* If property is configurable, there is no need for checks. */
    if (unlikely (!is_current_configurable))
    {
      if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDDATA)
      {
        // 10. a. i. & ii.
        if (!ecma_is_property_writable (current_p)
            && (property_desc_p->is_writable
                || (property_desc_p->is_value_defined
                    && !ecma_op_same_value (property_desc_p->value,
                                            ecma_get_named_data_property_value (current_p)))))
        {
          return ecma_reject (is_throw);
        }
      }
      else
      {
        // 11.

        // a.
        if ((property_desc_p->is_get_defined
             && property_desc_p->get_p != ecma_get_named_accessor_property_getter (current_p))
            || (property_desc_p->is_set_defined
                && property_desc_p->set_p != ecma_get_named_accessor_property_setter (current_p)))
        {
          // i., ii.
          return ecma_reject (is_throw);
        }
      }
    }
  }
  else
  {
    // 9.
    if (!is_current_configurable)
    {
      // a.
      return ecma_reject (is_throw);
    }

    /* The following implementation can be optimized by directly overwriting
     * the fields of current_p if this code path is performance critical. */

    bool was_enumerable = ecma_is_property_enumerable (current_p);

    ecma_delete_property (obj_p, current_p);

    if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR)
    {
      // b.

      current_p = ecma_create_named_accessor_property (obj_p,
                                                       property_name_p,
                                                       NULL,
                                                       NULL,
                                                       was_enumerable,
                                                       true);
    }
    else
    {
      // c.

      current_p = ecma_create_named_data_property (obj_p,
                                                   property_name_p,
                                                   false,
                                                   was_enumerable,
                                                   true);
    }
  }

  // 12.
  if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDDATA)
  {
    JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (current_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);

    if (property_desc_p->is_value_defined)
    {
      ecma_named_data_property_assign_value (obj_p, current_p, property_desc_p->value);
    }

    if (property_desc_p->is_writable_defined)
    {
      ecma_set_property_writable_attr (current_p, property_desc_p->is_writable);
    }
  }
  else if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR)
  {
    JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (current_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);

    if (property_desc_p->is_get_defined)
    {
      ecma_set_named_accessor_property_getter (obj_p, current_p, property_desc_p->get_p);
    }

    if (property_desc_p->is_set_defined)
    {
      ecma_set_named_accessor_property_setter (obj_p, current_p, property_desc_p->set_p);
    }
  }

  if (property_desc_p->is_enumerable_defined)
  {
    ecma_set_property_enumerable_attr (current_p, property_desc_p->is_enumerable);
  }

  if (property_desc_p->is_configurable_defined)
  {
    ecma_set_property_configurable_attr (current_p, property_desc_p->is_configurable);
  }

  return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
} /* ecma_op_general_object_define_own_property */
/**
 * PutValue operation part (object base).
 *
 * See also: ECMA-262 v5, 8.7.2, section 4
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
 */
ecma_value_t
ecma_op_put_value_object_base (ecma_reference_t ref, /**< ECMA-reference */
                               ecma_value_t value) /**< ECMA-value */
{
  const ecma_value_t base = ref.base;
  const bool is_unresolvable_reference = ecma_is_value_undefined (base);
  const bool has_primitive_base = (ecma_is_value_boolean (base)
                                   || ecma_is_value_number (base)
                                   || ecma_is_value_string (base));
  const bool has_object_base = (ecma_is_value_object (base)
                                && !(ecma_is_lexical_environment (ecma_get_object_from_value (base))));
  const bool is_property_reference = has_primitive_base || has_object_base;

  JERRY_ASSERT (!is_unresolvable_reference);
  JERRY_ASSERT (is_property_reference);

  // 4.a
  if (!has_primitive_base)
  {
    // 4.b case 1

    ecma_object_t *obj_p = ecma_get_object_from_value (base);
    JERRY_ASSERT (obj_p != NULL
                  && !ecma_is_lexical_environment (obj_p));

    ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

    ECMA_TRY_CATCH (put_ret_value,
                    ecma_op_object_put (obj_p,
                                        ECMA_GET_NON_NULL_POINTER (ecma_string_t,
                                                                   ref.referenced_name_cp),
                                        value,
                                        ref.is_strict),
                    ret_value);

    ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

    ECMA_FINALIZE (put_ret_value);

    return ret_value;
  }
  else
  {
    // 4.b case 2
    ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

    // sub_1.
    ECMA_TRY_CATCH (obj_base, ecma_op_to_object (base), ret_value);

    ecma_object_t *obj_p = ecma_get_object_from_value (obj_base);
    JERRY_ASSERT (obj_p != NULL
                  && !ecma_is_lexical_environment (obj_p));

    ecma_string_t *referenced_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
                                                                  ref.referenced_name_cp);

    // sub_2.
    if (!ecma_op_object_can_put (obj_p, referenced_name_p))
    {
      ret_value = ecma_reject_put (ref.is_strict);
    }
    else
    {
      // sub_3.
      ecma_property_t *own_prop_p = ecma_op_object_get_own_property (obj_p, referenced_name_p);

      // sub_5.
      ecma_property_t *prop_p = ecma_op_object_get_property (obj_p, referenced_name_p);

      // sub_4., sub_7
      if ((own_prop_p != NULL && (own_prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDDATA))
          || (prop_p == NULL)
          || !(prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDACCESSOR))
      {
        ret_value = ecma_reject_put (ref.is_strict);
      }
      else
      {
        // sub_6.
        JERRY_ASSERT (prop_p != NULL && (prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDACCESSOR));

        ecma_object_t *setter_p = ecma_get_named_accessor_property_setter (prop_p);
        JERRY_ASSERT (setter_p != NULL);

        ECMA_TRY_CATCH (call_ret,
                        ecma_op_function_call (setter_p, base, &value, 1),
                        ret_value);

        ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

        ECMA_FINALIZE (call_ret);
      }
    }

    ECMA_FINALIZE (obj_base);

    return ret_value;
  }
} /* ecma_op_put_value_object_base */
/**
 * [[DefineOwnProperty]] ecma Arguments object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 10.6
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value
 */
ecma_value_t
ecma_op_arguments_object_define_own_property (ecma_object_t *obj_p, /**< the 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 */
{
  // 1.
  ecma_property_t *map_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP);
  ecma_object_t *map_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ECMA_PROPERTY_VALUE_PTR (map_prop_p)->value);

  // 2.
  ecma_property_t *mapped_prop_p = ecma_op_object_get_own_property (map_p, property_name_p);

  // 3.
  ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  ECMA_TRY_CATCH (defined,
                  ecma_op_general_object_define_own_property (obj_p,
                                                              property_name_p,
                                                              property_desc_p,
                                                              is_throw),
                  ret_value);

  // 5.
  if (mapped_prop_p != NULL)
  {
    // a.
    if (property_desc_p->is_get_defined
        || property_desc_p->is_set_defined)
    {
      ecma_value_t completion = ecma_op_object_delete (map_p, property_name_p, false);

      JERRY_ASSERT (ecma_is_value_true (completion));

      // 6.
      ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
    }
    else
    {
      // b.

      ecma_value_t completion = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

      // i.
      if (property_desc_p->is_value_defined)
      {
        /* emulating execution of function described by MakeArgSetter */
        ecma_property_t *scope_prop_p = ecma_get_internal_property (map_p, ECMA_INTERNAL_PROPERTY_SCOPE);
        ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
                                                                    ECMA_PROPERTY_VALUE_PTR (scope_prop_p)->value);

        ecma_property_t *mapped_prop_p = ecma_op_object_get_own_property (map_p, property_name_p);
        ecma_value_t arg_name_prop_value = ecma_get_named_data_property_value (mapped_prop_p);

        ecma_string_t *arg_name_p = ecma_get_string_from_value (arg_name_prop_value);

        completion = ecma_op_set_mutable_binding (lex_env_p,
                                                  arg_name_p,
                                                  property_desc_p->value,
                                                  true);
        JERRY_ASSERT (ecma_is_value_empty (completion));
      }

      // ii.
      if (property_desc_p->is_writable_defined
          && !property_desc_p->is_writable)
      {
        completion = ecma_op_object_delete (map_p,
                                            property_name_p,
                                            false);

        JERRY_ASSERT (ecma_is_value_true (completion));
      }

      // 6.
      ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
    }
  }
  else
  {
    ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
  }

  ECMA_FINALIZE (defined);

  return ret_value;
} /* ecma_op_arguments_object_define_own_property */
Example #21
0
/**
 * List names of a built-in object's lazy instantiated properties
 *
 * See also:
 *          ecma_builtin_try_to_instantiate_property
 */
void
ecma_builtin_list_lazy_property_names (ecma_object_t *object_p, /**< a built-in object */
                                       bool separate_enumerable, /**< true -  list enumerable properties into
                                                                  *           main collection, and non-enumerable
                                                                  *           to collection of 'skipped non-enumerable'
                                                                  *           properties,
                                                                  *   false - list all properties into main collection.
                                                                  */
                                       ecma_collection_header_t *main_collection_p, /**< 'main' collection */
                                       ecma_collection_header_t *non_enum_collection_p) /**< skipped 'non-enumerable'
                                                                                         *   collection */
{
  JERRY_ASSERT (ecma_get_object_is_builtin (object_p));

  ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;

  if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION
      && ecma_builtin_function_is_routine (object_p))
  {
    ecma_collection_header_t *for_enumerable_p = main_collection_p;
    (void) for_enumerable_p;

    ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p;

    /* 'length' property is non-enumerable (ECMA-262 v5, 15) */
    ecma_string_t *name_p = ecma_new_ecma_length_string ();
    ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true);
    ecma_deref_ecma_string (name_p);
  }
  else
  {
    ecma_builtin_id_t builtin_id = (ecma_builtin_id_t) ext_obj_p->u.built_in.id;

    JERRY_ASSERT (builtin_id < ECMA_BUILTIN_ID__COUNT);
    JERRY_ASSERT (ecma_builtin_is (object_p, builtin_id));

    const ecma_builtin_property_descriptor_t *curr_property_p = ecma_builtin_property_list_references[builtin_id];

    ecma_length_t index = 0;
    uint32_t instantiated_bitset = ext_obj_p->u.built_in.instantiated_bitset;

    ecma_collection_header_t *for_non_enumerable_p = (separate_enumerable ? non_enum_collection_p
                                                                          : main_collection_p);

    while (curr_property_p->magic_string_id != LIT_MAGIC_STRING__COUNT)
    {
      JERRY_ASSERT (index < 64);

      if (index == 32)
      {
        ecma_property_t *mask_prop_p = ecma_find_internal_property (object_p,
                                                                    ECMA_INTERNAL_PROPERTY_INSTANTIATED_MASK_32_63);

        if (mask_prop_p == NULL)
        {
          instantiated_bitset = 0;
        }
        else
        {
          instantiated_bitset = ecma_get_internal_property_value (mask_prop_p);
        }
      }

      uint32_t bit_for_index;
      if (index >= 32)
      {
        bit_for_index = (uint32_t) 1u << (index - 32);
      }
      else
      {
        bit_for_index = (uint32_t) 1u << index;
      }

      bool was_instantiated = false;

      if (instantiated_bitset & bit_for_index)
      {
        was_instantiated = true;
      }

      ecma_string_t *name_p = ecma_get_magic_string (curr_property_p->magic_string_id);

      if (!was_instantiated || ecma_op_object_get_own_property (object_p, name_p) != NULL)
      {
        ecma_append_to_values_collection (for_non_enumerable_p,
                                          ecma_make_string_value (name_p),
                                          true);
      }

      ecma_deref_ecma_string (name_p);

      curr_property_p++;
      index++;
    }
  }
} /* ecma_builtin_list_lazy_property_names */
Example #22
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 */
/**
 * [[Put]] ecma general object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 8.12.5
 *          Also incorporates [[CanPut]] ECMA-262 v5, 8.12.4
 *
 * @return ecma value
 *         The returned value must be freed with ecma_free_value.
 *
 *         Returns with ECMA_SIMPLE_VALUE_TRUE if the operation is
 *         successful. Otherwise it returns with an error object
 *         or ECMA_SIMPLE_VALUE_FALSE.
 *
 *         Note: even if is_throw is false, the setter can throw an
 *         error, and this function returns with that error.
 */
ecma_value_t
ecma_op_general_object_put (ecma_object_t *obj_p, /**< the object */
                            ecma_string_t *property_name_p, /**< property name */
                            ecma_value_t value, /**< ecma value */
                            bool is_throw) /**< flag that controls failure handling */
{
  JERRY_ASSERT (obj_p != NULL
                && !ecma_is_lexical_environment (obj_p));
  JERRY_ASSERT (property_name_p != NULL);

  ecma_object_t *setter_p = NULL;

  ecma_property_t *prop_p = ecma_op_object_get_own_property (obj_p, property_name_p);

  if (prop_p != NULL)
  {
    if (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA)
    {
      if (ecma_is_property_writable (prop_p))
      {
        const ecma_object_type_t type = ecma_get_object_type (obj_p);

        if (type == ECMA_OBJECT_TYPE_ARGUMENTS
            || (type == ECMA_OBJECT_TYPE_ARRAY && ecma_op_general_object_property_name_is_length (property_name_p)))
        {
          /* These cases cannot be optimized. */
          ecma_property_descriptor_t value_desc = ecma_make_empty_property_descriptor ();

          value_desc.is_value_defined = true;
          value_desc.value = value;

          return ecma_op_object_define_own_property (obj_p,
                                                     property_name_p,
                                                     &value_desc,
                                                     is_throw);
        }

        /* There is no need for special casing arrays here because changing the
         * value of an existing property never changes the length of an array. */
        ecma_named_data_property_assign_value (obj_p, prop_p, value);
        return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
      }
    }
    else
    {
      JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);

      setter_p = ecma_get_named_accessor_property_setter (prop_p);
    }
  }
  else
  {
    ecma_object_t *proto_p = ecma_get_object_prototype (obj_p);
    bool create_new_property = true;

    if (proto_p != NULL)
    {
      ecma_property_t *inherited_prop_p = ecma_op_object_get_property (proto_p, property_name_p);

      if (inherited_prop_p != NULL)
      {
        if (ECMA_PROPERTY_GET_TYPE (inherited_prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR)
        {
          setter_p = ecma_get_named_accessor_property_setter (inherited_prop_p);
          create_new_property = false;
        }
        else
        {
          create_new_property = ecma_is_property_writable (inherited_prop_p);
        }
      }
    }

    if (create_new_property
        && ecma_get_object_extensible (obj_p))
    {
      const ecma_object_type_t type = ecma_get_object_type (obj_p);

      if (type == ECMA_OBJECT_TYPE_ARGUMENTS)
      {
        return ecma_builtin_helper_def_prop (obj_p,
                                             property_name_p,
                                             value,
                                             true, /* Writable */
                                             true, /* Enumerable */
                                             true, /* Configurable */
                                             is_throw); /* Failure handling */
      }

      uint32_t index;

      if (type == ECMA_OBJECT_TYPE_ARRAY
          && ecma_string_get_array_index (property_name_p, &index))
      {
        /* Since the length of an array is a non-configurable named data
         * property, the prop_p must be a non-NULL pointer for all arrays. */

        JERRY_ASSERT (!ecma_op_general_object_property_name_is_length (property_name_p));

        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);
        ecma_deref_ecma_string (magic_string_length_p);

        JERRY_ASSERT (len_prop_p != NULL
                      && ECMA_PROPERTY_GET_TYPE (len_prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);

        uint32_t old_len = ecma_get_uint32_from_value (ecma_get_named_data_property_value (len_prop_p));

        if (index < UINT32_MAX
            && index >= old_len)
        {
          if (!ecma_is_property_writable (len_prop_p))
          {
            return ecma_reject (is_throw);
          }

          ecma_property_value_t *len_prop_value_p = ECMA_PROPERTY_VALUE_PTR (len_prop_p);
          ecma_value_assign_uint32 (&len_prop_value_p->value, index + 1);
        }
      }

      ecma_property_t *new_prop_p = ecma_create_named_data_property (obj_p,
                                                                     property_name_p,
                                                                     true, /* Writable */
                                                                     true, /* Enumerable */
                                                                     true); /* Configurable */

      JERRY_ASSERT (ecma_is_value_undefined (ecma_get_named_data_property_value (new_prop_p)));
      ecma_set_named_data_property_value (new_prop_p, ecma_copy_value_if_not_object (value));
      return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
    }
  }

  if (setter_p == NULL)
  {
    return ecma_reject (is_throw);
  }

  ecma_value_t ret_value = ecma_op_function_call (setter_p,
                                                  ecma_make_object_value (obj_p),
                                                  &value,
                                                  1);

  if (!ecma_is_value_error (ret_value))
  {
    ecma_fast_free_value (ret_value);
    ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
  }

  return ret_value;
} /* ecma_op_general_object_put */