Exemple #1
0
/**
 * Create named accessor property with given name, attributes, getter and setter.
 *
 * @return pointer to newly created property
 */
ecma_property_t *
ecma_create_named_accessor_property (ecma_object_t *object_p, /**< object */
                                     ecma_string_t *name_p, /**< property name */
                                     ecma_object_t *get_p, /**< getter */
                                     ecma_object_t *set_p, /**< setter */
                                     bool is_enumerable, /**< 'enumerable' attribute */
                                     bool is_configurable) /**< 'configurable' attribute */
{
  JERRY_ASSERT (object_p != NULL && name_p != NULL);
  JERRY_ASSERT (ecma_find_named_property (object_p, name_p) == NULL);

  uint8_t type_and_flags = ECMA_PROPERTY_TYPE_NAMEDACCESSOR;
  if (is_configurable)
  {
    type_and_flags = (uint8_t) (type_and_flags | ECMA_PROPERTY_FLAG_CONFIGURABLE);
  }
  if (is_enumerable)
  {
    type_and_flags = (uint8_t) (type_and_flags | ECMA_PROPERTY_FLAG_ENUMERABLE);
  }

  name_p = ecma_copy_or_ref_ecma_string (name_p);

  ecma_property_t *property_p = ecma_create_property (object_p, name_p, type_and_flags);

  /*
   * Should be performed after linking the property into object's property list, because the setters assert that.
   */
  ecma_set_named_accessor_property_getter (object_p, property_p, get_p);
  ecma_set_named_accessor_property_setter (object_p, property_p, set_p);

  ecma_lcache_invalidate (object_p, name_p, NULL);

  return property_p;
} /* ecma_create_named_accessor_property */
Exemple #2
0
/**
 * Update getter or setter for object literals.
 */
void
opfunc_set_accessor (bool is_getter, /**< is getter accessor */
                     ecma_value_t object, /**< object value */
                     ecma_value_t accessor_name, /**< accessor name value */
                     ecma_value_t accessor) /**< accessor value */
{
  ecma_object_t *object_p = ecma_get_object_from_value (object);
  JERRY_ASSERT (ecma_is_value_string (accessor_name) || ecma_is_value_number (accessor_name));
  ecma_string_t *accessor_name_p = ecma_get_string_from_value (ecma_op_to_string (accessor_name));
  ecma_property_t *property_p = ecma_find_named_property (object_p, accessor_name_p);

  if (property_p != NULL
      && ECMA_PROPERTY_GET_TYPE (*property_p) != ECMA_PROPERTY_TYPE_NAMEDACCESSOR)
  {
    ecma_delete_property (object_p, ECMA_PROPERTY_VALUE_PTR (property_p));
    property_p = NULL;
  }

  if (property_p == NULL)
  {
    ecma_object_t *getter_func_p = NULL;
    ecma_object_t *setter_func_p = NULL;

    if (is_getter)
    {
      getter_func_p = ecma_get_object_from_value (accessor);
    }
    else
    {
      setter_func_p = ecma_get_object_from_value (accessor);
    }

    ecma_create_named_accessor_property (object_p,
                                         accessor_name_p,
                                         getter_func_p,
                                         setter_func_p,
                                         ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE,
                                         NULL);
  }
  else if (is_getter)
  {
    ecma_object_t *getter_func_p = ecma_get_object_from_value (accessor);

    ecma_set_named_accessor_property_getter (object_p,
                                             ECMA_PROPERTY_VALUE_PTR (property_p),
                                             getter_func_p);
  }
  else
  {
    ecma_object_t *setter_func_p = ecma_get_object_from_value (accessor);

    ecma_set_named_accessor_property_setter (object_p,
                                             ECMA_PROPERTY_VALUE_PTR (property_p),
                                             setter_func_p);
  }

  ecma_deref_ecma_string (accessor_name_p);
} /* opfunc_set_accessor */
Exemple #3
0
/**
 * Update getter or setter for object literals.
 */
void
opfunc_set_accessor (bool is_getter, /**< is getter accessor */
                     ecma_value_t object, /**< object value */
                     ecma_value_t accessor_name, /**< accessor name value */
                     ecma_value_t accessor) /**< accessor value */
{
  ecma_object_t *object_p = ecma_get_object_from_value (object);
  ecma_string_t *accessor_name_p = ecma_get_string_from_value (accessor_name);
  ecma_property_t *property_p = ecma_find_named_property (object_p, accessor_name_p);

  if (property_p != NULL && property_p->type != ECMA_PROPERTY_NAMEDACCESSOR)
  {
    ecma_delete_property (object_p, property_p);
    property_p = NULL;
  }

  if (property_p == NULL)
  {
    ecma_object_t *getter_func_p = NULL;
    ecma_object_t *setter_func_p = NULL;

    if (is_getter)
    {
      getter_func_p = ecma_get_object_from_value (accessor);
    }
    else
    {
      setter_func_p = ecma_get_object_from_value (accessor);
    }

    ecma_create_named_accessor_property (object_p,
                                         accessor_name_p,
                                         getter_func_p,
                                         setter_func_p,
                                         true,
                                         true);
  }
  else if (is_getter)
  {
    ecma_object_t *getter_func_p = ecma_get_object_from_value (accessor);

    ecma_set_named_accessor_property_getter (object_p,
                                             property_p,
                                             getter_func_p);
  }
  else
  {
    ecma_object_t *setter_func_p = ecma_get_object_from_value (accessor);

    ecma_set_named_accessor_property_setter (object_p,
                                             property_p,
                                             setter_func_p);
  }
} /* opfunc_set_accessor */
/**
 * [[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 */
/**
 * [[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 */