Exemple #1
0
/**
 * Insert an entry into LCache
 */
void
ecma_lcache_insert (ecma_object_t *object_p, /**< object */
                    jmem_cpointer_t name_cp, /**< property name */
                    ecma_property_t *prop_p) /**< property */
{
  JERRY_ASSERT (object_p != NULL);
  JERRY_ASSERT (prop_p != NULL && !ecma_is_property_lcached (prop_p));
  JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
                || ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);

#ifndef CONFIG_ECMA_LCACHE_DISABLE
  jmem_cpointer_t object_cp;

  ECMA_SET_NON_NULL_POINTER (object_cp, object_p);

  lit_string_hash_t name_hash = ecma_string_get_property_name_hash (*prop_p, name_cp);
  size_t row_index = ecma_lcache_row_index (object_cp, name_hash);
  ecma_lcache_hash_entry_t *entries_p = JERRY_HASH_TABLE_CONTEXT (table)[row_index];

  int32_t entry_index;
  for (entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++)
  {
    if (entries_p[entry_index].object_cp == ECMA_NULL_POINTER)
    {
      break;
    }
  }

  if (entry_index == ECMA_LCACHE_HASH_ROW_LENGTH)
  {
    /* Invalidate the last entry. */
    ecma_lcache_invalidate_entry (entries_p + ECMA_LCACHE_HASH_ROW_LENGTH - 1);

    /* Shift other entries towards the end. */
    for (uint32_t i = ECMA_LCACHE_HASH_ROW_LENGTH - 1; i > 0; i--)
    {
      entries_p[i] = entries_p[i - 1];
    }

    entry_index = 0;
  }

  ecma_lcache_hash_entry_t *entry_p = entries_p + entry_index;
  ECMA_SET_NON_NULL_POINTER (entry_p->object_cp, object_p);
  entry_p->prop_name_cp = name_cp;
  entry_p->prop_p = prop_p;

  ecma_set_property_lcached (entry_p->prop_p, true);
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
} /* ecma_lcache_insert */
Exemple #2
0
/**
 * Create a object lexical environment with specified outer lexical environment
 * (or NULL if the environment is not nested), binding object and provideThis flag.
 *
 * See also: ECMA-262 v5, 10.2.1.2
 *
 * Reference counter's value will be set to one.
 *
 * @return pointer to the descriptor of lexical environment
 */
ecma_object_t *
ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, /**< outer lexical environment */
                            ecma_object_t *binding_obj_p, /**< binding object */
                            bool provide_this) /**< provideThis flag */
{
  JERRY_ASSERT (binding_obj_p != NULL
                && !ecma_is_lexical_environment (binding_obj_p));

  ecma_object_t *new_lexical_environment_p = ecma_alloc_object ();

  uint16_t type;

  if (provide_this)
  {
    type = ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND;
  }
  else
  {
    type = ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND;
  }

  new_lexical_environment_p->type_flags_refs = type;

  ecma_init_gc_info (new_lexical_environment_p);

  ECMA_SET_NON_NULL_POINTER (new_lexical_environment_p->property_list_or_bound_object_cp,
                             binding_obj_p);

  ECMA_SET_POINTER (new_lexical_environment_p->prototype_or_outer_reference_cp,
                    outer_lexical_environment_p);

  return new_lexical_environment_p;
} /* ecma_create_object_lex_env */
Exemple #3
0
/**
 * Invalidate LCache entries associated with given object and property name / property
 *
 * Note:
 *      Either property name argument or property argument should be NULL,
 *      and another should be non-NULL.
 *      In case property name argument is NULL, property's name is taken
 *      from property's description.
 */
void
ecma_lcache_invalidate (ecma_object_t *object_p, /**< object */
                        ecma_string_t *prop_name_p, /**< property's name (See also: Note) */
                        ecma_property_t *prop_p) /**< property (See also: Note) */
{
  JERRY_ASSERT (object_p != NULL);
  JERRY_ASSERT (prop_name_p != NULL);

#ifndef CONFIG_ECMA_LCACHE_DISABLE
  if (prop_p != NULL)
  {
    JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
                  || ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);

    bool is_cached = ecma_is_property_lcached (prop_p);

    if (!is_cached)
    {
      return;
    }

    ecma_set_property_lcached (prop_p, false);
  }

  unsigned int object_cp;
  ECMA_SET_NON_NULL_POINTER (object_cp, object_p);

  lit_string_hash_t hash_key = ecma_string_hash (prop_name_p);

  /* Property's name has was computed.
   * Given (object, property name) pair should be in the row corresponding to computed hash.
   */
  ecma_lcache_invalidate_row_for_object_property_pair (hash_key, object_cp, prop_p);
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
} /* ecma_lcache_invalidate */
/**
 * General iterator object creation operation.
 *
 * See also: ECMA-262 v6, 21.1.5.1, 22.1.5.1, 23.1.5.1
 *
 * Note:
 *      Returned value must be freed with ecma_free_value.
 *
 * @return iterator object
 */
ecma_value_t
ecma_op_create_iterator_object (ecma_value_t iterated_value, /**< value from create iterator */
                                ecma_object_t *prototype_obj_p, /**< prototype object */
                                uint8_t iterator_type, /**< itertator type, see ecma_pseudo_array_type_t */
                                uint8_t extra_info) /**< extra information */
{
  /* 1. */
  JERRY_ASSERT (ecma_is_value_object (iterated_value));
  JERRY_ASSERT (iterator_type >= ECMA_PSEUDO_ARRAY_ITERATOR && iterator_type <= ECMA_PSEUDO_ARRAY__MAX);

  ecma_object_t *iterated_obj_p = ecma_get_object_from_value (iterated_value);
  /* 2. */
  ecma_object_t *object_p = ecma_create_object (prototype_obj_p,
                                                sizeof (ecma_extended_object_t),
                                                ECMA_OBJECT_TYPE_PSEUDO_ARRAY);

  ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
  ext_obj_p->u.pseudo_array.type = iterator_type;

  /* 3. */
  ECMA_SET_NON_NULL_POINTER (ext_obj_p->u.pseudo_array.u2.iterated_value_cp, iterated_obj_p);
  /* 4. */
  ext_obj_p->u.pseudo_array.u1.iterator_index = 0;
  /* 5. */
  ext_obj_p->u.pseudo_array.extra_info = extra_info;

  /* 6. */
  return ecma_make_object_value (object_p);
} /* ecma_op_create_iterator_object */
Exemple #5
0
/**
 * Invalidate LCache entries associated with given object and property name / property
 */
void
ecma_lcache_invalidate (ecma_object_t *object_p, /**< object */
                        jmem_cpointer_t name_cp, /**< property name */
                        ecma_property_t *prop_p) /**< property */
{
  JERRY_ASSERT (object_p != NULL);
  JERRY_ASSERT (prop_p != NULL && ecma_is_property_lcached (prop_p));
  JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
                || ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);

#ifndef CONFIG_ECMA_LCACHE_DISABLE
  jmem_cpointer_t object_cp;
  ECMA_SET_NON_NULL_POINTER (object_cp, object_p);

  lit_string_hash_t name_hash = ecma_string_get_property_name_hash (*prop_p, name_cp);
  size_t row_index = ecma_lcache_row_index (object_cp, name_hash);
  ecma_lcache_hash_entry_t *entry_p = JERRY_HASH_TABLE_CONTEXT (table) [row_index];

  for (uint32_t entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++)
  {
    if (entry_p->object_cp != ECMA_NULL_POINTER && entry_p->prop_p == prop_p)
    {
      JERRY_ASSERT (entry_p->object_cp == object_cp);

      ecma_lcache_invalidate_entry (entry_p);
      return;
    }
    entry_p++;
  }

  /* The property must be present. */
  JERRY_UNREACHABLE ();
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
} /* ecma_lcache_invalidate */
/**
 * Remove last element of the collection
 *
 * Warning:
 *         the function invalidates all iterators that are configured to access the passed collection
 */
void
ecma_remove_last_value_from_values_collection (ecma_collection_header_t *header_p, /**< collection's header */
                                               bool do_deref_if_object) /**< if the value to remove
                                                                         *   is object value, decrement
                                                                         *   reference counter of the object */
{
  JERRY_ASSERT (header_p != NULL && header_p->unit_number > 0);

  const size_t values_in_chunk = sizeof (ecma_collection_chunk_t::data) / sizeof (ecma_value_t);
  size_t values_number = header_p->unit_number;
  size_t pos_of_value_to_remove_in_chunk = (values_number - 1u) % values_in_chunk;

  ecma_collection_chunk_t *last_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
                                                                     header_p->last_chunk_cp);

  ecma_value_t *values_p = (ecma_value_t *) last_chunk_p->data;
  JERRY_ASSERT ((uint8_t *) (values_p + pos_of_value_to_remove_in_chunk + 1) <= (uint8_t *) (last_chunk_p + 1));

  ecma_value_t value_to_remove = values_p[pos_of_value_to_remove_in_chunk];

  ecma_free_value (value_to_remove, do_deref_if_object);

  header_p->unit_number--;

  if (pos_of_value_to_remove_in_chunk == 0)
  {
    ecma_collection_chunk_t *chunk_to_remove_p = last_chunk_p;

    /* free last chunk */
    if (header_p->first_chunk_cp == header_p->last_chunk_cp)
    {
      header_p->first_chunk_cp = ECMA_NULL_POINTER;
      header_p->last_chunk_cp = ECMA_NULL_POINTER;
    }
    else
    {
      ecma_collection_chunk_t *chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
                                                                         header_p->first_chunk_cp);

      while (chunk_iter_p->next_chunk_cp != header_p->last_chunk_cp)
      {
        chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
                                                  chunk_iter_p->next_chunk_cp);
      }

      ecma_collection_chunk_t *new_last_chunk_p = chunk_iter_p;

      JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
                                               new_last_chunk_p->next_chunk_cp) == chunk_to_remove_p);

      ECMA_SET_NON_NULL_POINTER (header_p->last_chunk_cp, new_last_chunk_p);
      new_last_chunk_p->next_chunk_cp = ECMA_NULL_POINTER;
    }

    ecma_dealloc_collection_chunk (chunk_to_remove_p);
  }
} /* ecma_remove_last_value_from_values_collection */
/**
 * Remove last element of the collection
 *
 * Warning:
 *         the function invalidates all iterators that are configured to access the passed collection
 */
void
ecma_remove_last_value_from_values_collection (ecma_collection_header_t *header_p) /**< collection's header */
{
  JERRY_ASSERT (header_p != NULL && header_p->unit_number > 0);

  const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t);
  size_t values_number = header_p->unit_number;
  size_t pos_of_value_to_remove_in_chunk = (values_number - 1u) % values_in_chunk;

  ecma_collection_chunk_t *last_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
                                                                     header_p->last_chunk_cp);

  ecma_value_t *values_p = (ecma_value_t *) last_chunk_p->data;
  JERRY_ASSERT ((uint8_t *) (values_p + pos_of_value_to_remove_in_chunk + 1) <= (uint8_t *) (last_chunk_p + 1));

  ecma_value_t value_to_remove = values_p[pos_of_value_to_remove_in_chunk];

  ecma_free_value (value_to_remove);

  header_p->unit_number--;

  if (pos_of_value_to_remove_in_chunk == 0)
  {
    ecma_collection_chunk_t *chunk_to_remove_p = last_chunk_p;

    /* free last chunk */
    if (header_p->first_chunk_cp == header_p->last_chunk_cp)
    {
      header_p->first_chunk_cp = ECMA_NULL_POINTER;
      header_p->last_chunk_cp = ECMA_NULL_POINTER;
    }
    else
    {
      ecma_collection_chunk_t *chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
                                                                         header_p->first_chunk_cp);

      while (chunk_iter_p->next_chunk_cp != header_p->last_chunk_cp)
      {
        chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
                                                  chunk_iter_p->next_chunk_cp);
      }

      ecma_collection_chunk_t *new_last_chunk_p = chunk_iter_p;

      JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
                                               new_last_chunk_p->next_chunk_cp) == chunk_to_remove_p);

      ECMA_SET_NON_NULL_POINTER (header_p->last_chunk_cp, new_last_chunk_p);
      new_last_chunk_p->next_chunk_cp = ECMA_NULL_POINTER;
    }

    ecma_dealloc_collection_chunk (chunk_to_remove_p);
  }
} /* ecma_remove_last_value_from_values_collection */
/**
 * Create internal property with specified identifier and store external pointer in the property.
 *
 * Note:
 *      property identifier should be one of the following:
 *        - ECMA_INTERNAL_PROPERTY_NATIVE_CODE;
 *        - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE;
 *        - ECMA_INTERNAL_PROPERTY_FREE_CALLBACK.
 *
 * @return true - if property was just created with specified value,
 *         false - otherwise, if property existed before the call, it's value was updated.
 */
bool
ecma_create_external_pointer_property (ecma_object_t *obj_p, /**< object to create property in */
                                       ecma_internal_property_id_t id, /**< identifier of internal
                                                                        *   property to create */
                                       ecma_external_pointer_t ptr_value) /**< value to store in the property */
{
  JERRY_ASSERT (id == ECMA_INTERNAL_PROPERTY_NATIVE_CODE
                || id == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE
                || id == ECMA_INTERNAL_PROPERTY_FREE_CALLBACK);

  bool is_new;
  ecma_property_t *prop_p = ecma_find_internal_property (obj_p, id);

  if (prop_p == NULL)
  {
    prop_p = ecma_create_internal_property (obj_p, id);

    is_new = true;
  }
  else
  {
    is_new = false;
  }

  JERRY_STATIC_ASSERT (sizeof (uint32_t) <= sizeof (ECMA_PROPERTY_VALUE_PTR (prop_p)->value),
                       size_of_internal_property_value_must_be_greater_than_or_equal_to_4_bytes);

  if (sizeof (ecma_external_pointer_t) == sizeof (uint32_t))
  {
    ECMA_PROPERTY_VALUE_PTR (prop_p)->value = (uint32_t) ptr_value;
  }
  else
  {
    ecma_external_pointer_t *handler_p;

    if (is_new)
    {
      handler_p = ecma_alloc_external_pointer ();

      ECMA_SET_NON_NULL_POINTER (ECMA_PROPERTY_VALUE_PTR (prop_p)->value, handler_p);
    }
    else
    {
      handler_p = ECMA_GET_NON_NULL_POINTER (ecma_external_pointer_t,
                                             ECMA_PROPERTY_VALUE_PTR (prop_p)->value);
    }

    *handler_p = ptr_value;
  }

  return is_new;
} /* ecma_create_external_pointer_property */
Exemple #9
0
/**
 * Lookup property in the LCache
 *
 * @return true - if (object, property name) pair is registered in LCache,
 *         false - probably, not registered.
 */
inline bool __attr_always_inline___
ecma_lcache_lookup (ecma_object_t *object_p, /**< object */
                    const ecma_string_t *prop_name_p, /**< property's name */
                    ecma_property_t **prop_p_p) /**< [out] if return value is true,
                                                 *         then here will be pointer to property,
                                                 *         if the object contains property with specified name,
                                                 *         or, otherwise - NULL;
                                                 *         if return value is false,
                                                 *         then the output parameter is not set */
{
#ifndef CONFIG_ECMA_LCACHE_DISABLE
  lit_string_hash_t hash_key = ecma_string_hash (prop_name_p);

  unsigned int object_cp;
  ECMA_SET_NON_NULL_POINTER (object_cp, object_p);

  for (uint32_t i = 0; i < ECMA_LCACHE_HASH_ROW_LENGTH; i++)
  {
    if (ecma_lcache_hash_table[hash_key][i].object_cp == object_cp)
    {
      ecma_string_t *entry_prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
                                                                    ecma_lcache_hash_table[hash_key][i].prop_name_cp);

      JERRY_ASSERT (prop_name_p->hash == entry_prop_name_p->hash);

      if (ECMA_STRING_GET_CONTAINER (prop_name_p) == ECMA_STRING_GET_CONTAINER (entry_prop_name_p)
          && prop_name_p->u.common_field == entry_prop_name_p->u.common_field)
      {
        ecma_property_t *prop_p = ecma_lcache_hash_table[hash_key][i].prop_p;
        JERRY_ASSERT (prop_p == NULL || ecma_is_property_lcached (prop_p));

        *prop_p_p = prop_p;

        return true;
      }
      else
      {
        /* may be equal but it is long to compare it here */
      }
    }
  }
#else /* CONFIG_ECMA_LCACHE_DISABLE */
  (void) object_p;
  (void) prop_name_p;
  (void) prop_p_p;
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */

  return false;
} /* ecma_lcache_lookup */
/**
 * Number value constructor
 */
ecma_value_t __attr_const___
ecma_make_number_value (const ecma_number_t *num_p) /**< number to reference in value */
{
  JERRY_ASSERT (num_p != NULL);

  mem_cpointer_t num_cp;
  ECMA_SET_NON_NULL_POINTER (num_cp, num_p);

  ecma_value_t ret_value = 0;

  ret_value = ecma_set_value_type_field (ret_value, ECMA_TYPE_NUMBER);
  ret_value = ecma_set_value_value_field (ret_value, num_cp);

  return ret_value;
} /* ecma_make_number_value */
/**
 * Object value constructor
 */
ecma_value_t __attr_const___
ecma_make_object_value (const ecma_object_t *object_p) /**< object to reference in value */
{
  JERRY_ASSERT (object_p != NULL);

  mem_cpointer_t object_cp;
  ECMA_SET_NON_NULL_POINTER (object_cp, object_p);

  ecma_value_t ret_value = 0;

  ret_value = ecma_set_value_type_field (ret_value, ECMA_TYPE_OBJECT);
  ret_value = ecma_set_value_value_field (ret_value, object_cp);

  return ret_value;
} /* ecma_make_object_value */
/**
 * String value constructor
 */
ecma_value_t __attr_const___
ecma_make_string_value (const ecma_string_t *ecma_string_p) /**< string to reference in value */
{
  JERRY_ASSERT (ecma_string_p != NULL);

  mem_cpointer_t string_cp;
  ECMA_SET_NON_NULL_POINTER (string_cp, ecma_string_p);

  ecma_value_t ret_value = 0;

  ret_value = ecma_set_value_type_field (ret_value, ECMA_TYPE_STRING);
  ret_value = ecma_set_value_value_field (ret_value, string_cp);

  return ret_value;
} /* ecma_make_string_value */
Exemple #13
0
/**
 * Lookup property in the LCache
 *
 * @return a pointer to an ecma_property_t if the lookup is successful
 *         NULL otherwise
 */
inline ecma_property_t * __attr_always_inline___
ecma_lcache_lookup (ecma_object_t *object_p, /**< object */
                    const ecma_string_t *prop_name_p) /**< property's name */
{
  JERRY_ASSERT (object_p != NULL);
  JERRY_ASSERT (prop_name_p != NULL);

#ifndef CONFIG_ECMA_LCACHE_DISABLE
  jmem_cpointer_t object_cp;
  ECMA_SET_NON_NULL_POINTER (object_cp, object_p);

  size_t row_index = ecma_lcache_row_index (object_cp, prop_name_p);
  ecma_lcache_hash_entry_t *entry_p = JERRY_HASH_TABLE_CONTEXT (table) [row_index];
  ecma_lcache_hash_entry_t *entry_end_p = entry_p + ECMA_LCACHE_HASH_ROW_LENGTH;
  ecma_string_container_t prop_container = ECMA_STRING_GET_CONTAINER (prop_name_p);

  while (entry_p < entry_end_p)
  {
    if (entry_p->object_cp == object_cp)
    {
      ecma_string_t *entry_prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
                                                                    entry_p->prop_name_cp);

      JERRY_ASSERT ((prop_name_p->hash & ECMA_LCACHE_HASH_MASK) == (entry_prop_name_p->hash & ECMA_LCACHE_HASH_MASK));

      if (prop_name_p == entry_prop_name_p
          || (prop_container > ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING
              && prop_container == ECMA_STRING_GET_CONTAINER (entry_prop_name_p)
              && prop_name_p->u.common_field == entry_prop_name_p->u.common_field))
      {
        ecma_property_t *prop_p = entry_p->prop_p;
        JERRY_ASSERT (prop_p != NULL && ecma_is_property_lcached (prop_p));

        return prop_p;
      }
      else
      {
        /* They can be equal, but generic string comparison is too costly. */
      }
    }
    entry_p++;
  }
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */

  return NULL;
} /* ecma_lcache_lookup */
/**
 * Create internal property with specified identifier and store external pointer in the property.
 *
 * Note:
 *      property identifier should be one of the following:
 *        - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE;
 *        - ECMA_INTERNAL_PROPERTY_FREE_CALLBACK.
 *
 * @return true - if property was just created with specified value,
 *         false - otherwise, if property existed before the call, it's value was updated.
 */
bool
ecma_create_external_pointer_property (ecma_object_t *obj_p, /**< object to create property in */
                                       ecma_internal_property_id_t id, /**< identifier of internal
                                                                        *   property to create */
                                       ecma_external_pointer_t ptr_value) /**< value to store in the property */
{
  JERRY_ASSERT (id == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE
                || id == ECMA_INTERNAL_PROPERTY_FREE_CALLBACK);

  ecma_value_t *prop_p = ecma_find_internal_property (obj_p, id);
  bool is_new = (prop_p == NULL);

  if (is_new)
  {
    prop_p = ecma_create_internal_property (obj_p, id);
  }

  JERRY_STATIC_ASSERT (sizeof (uint32_t) <= sizeof (ECMA_PROPERTY_VALUE_PTR (prop_p)->value),
                       size_of_internal_property_value_must_be_greater_than_or_equal_to_4_bytes);

#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY

  *prop_p = (ecma_value_t) ptr_value;

#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */

  ecma_external_pointer_t *handler_p;

  if (is_new)
  {
    handler_p = ecma_alloc_external_pointer ();

    ECMA_SET_NON_NULL_POINTER (*prop_p, handler_p);
  }
  else
  {
    handler_p = ECMA_GET_NON_NULL_POINTER (ecma_external_pointer_t, *prop_p);
  }

  *handler_p = ptr_value;

#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */

  return is_new;
} /* ecma_create_external_pointer_property */
Exemple #15
0
/**
 * Lookup property in the LCache
 *
 * @return a pointer to an ecma_property_t if the lookup is successful
 *         NULL otherwise
 */
inline ecma_property_t * __attr_always_inline___
ecma_lcache_lookup (ecma_object_t *object_p, /**< object */
                    const ecma_string_t *prop_name_p) /**< property's name */
{
  JERRY_ASSERT (object_p != NULL);
  JERRY_ASSERT (prop_name_p != NULL);

#ifndef CONFIG_ECMA_LCACHE_DISABLE
  jmem_cpointer_t object_cp;
  ECMA_SET_NON_NULL_POINTER (object_cp, object_p);

  size_t row_index = ecma_lcache_row_index (object_cp, ecma_string_hash (prop_name_p));
  ecma_lcache_hash_entry_t *entry_p = JERRY_HASH_TABLE_CONTEXT (table) [row_index];
  ecma_lcache_hash_entry_t *entry_end_p = entry_p + ECMA_LCACHE_HASH_ROW_LENGTH;

  ecma_property_t prop_name_type;
  jmem_cpointer_t prop_name_cp = ecma_string_to_lcache_property_name (prop_name_p, &prop_name_type);

  while (entry_p < entry_end_p)
  {
    if (entry_p->object_cp == object_cp
        && entry_p->prop_name_cp == prop_name_cp)
    {
      ecma_property_t *prop_p = entry_p->prop_p;

      JERRY_ASSERT (prop_p != NULL && ecma_is_property_lcached (prop_p));

      if (ECMA_PROPERTY_GET_NAME_TYPE (*prop_p) == prop_name_type)
      {
        return prop_p;
      }
    }
    else
    {
      /* They can be equal, but generic string comparison is too costly. */
    }

    entry_p++;
  }
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */

  return NULL;
} /* ecma_lcache_lookup */
Exemple #16
0
/**
 * Converts a string into a property name
 *
 * @return the compressed pointer part of the name
 */
static inline jmem_cpointer_t __attr_always_inline___
ecma_string_to_lcache_property_name (const ecma_string_t *prop_name_p, /**< property name */
                                     ecma_property_t *name_type_p) /**< [out] property name type */
{
  ecma_string_container_t container = ECMA_STRING_GET_CONTAINER (prop_name_p);

  switch (container)
  {
    case ECMA_STRING_CONTAINER_UINT32_IN_DESC:
    case ECMA_STRING_CONTAINER_MAGIC_STRING:
    case ECMA_STRING_CONTAINER_MAGIC_STRING_EX:
    {
#ifdef JERRY_CPOINTER_32_BIT

      *name_type_p = (ecma_property_t) container;
      return (jmem_cpointer_t) prop_name_p->u.uint32_number;

#else /* !JERRY_CPOINTER_32_BIT */

      if (prop_name_p->u.uint32_number < (UINT16_MAX + 1))
      {
        *name_type_p = (ecma_property_t) container;
        return (jmem_cpointer_t) prop_name_p->u.uint32_number;
      }

#endif /* JERRY_CPOINTER_32_BIT */

      break;
    }
    default:
    {
      break;
    }
  }

  *name_type_p = ECMA_PROPERTY_NAME_TYPE_STRING;

  jmem_cpointer_t prop_name_cp;
  ECMA_SET_NON_NULL_POINTER (prop_name_cp, prop_name_p);
  return prop_name_cp;
} /* ecma_string_to_lcache_property_name */
/**
 * Create internal property with specified identifier and store external pointer in the property.
 *
 * Note:
 *      property identifier should be one of the following:
 *        - ECMA_INTERNAL_PROPERTY_NATIVE_CODE;
 *        - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE;
 *        - ECMA_INTERNAL_PROPERTY_FREE_CALLBACK.
 *
 * @return true - if property was just created with specified value,
 *         false - otherwise, if property existed before the call, it's value was updated.
 */
bool
ecma_create_external_pointer_property (ecma_object_t *obj_p, /**< object to create property in */
                                       ecma_internal_property_id_t id, /**< identifier of internal
                                                                        *   property to create */
                                       ecma_external_pointer_t ptr_value) /**< value to store in the property */
{
  JERRY_ASSERT (id == ECMA_INTERNAL_PROPERTY_NATIVE_CODE
                || id == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE
                || id == ECMA_INTERNAL_PROPERTY_FREE_CALLBACK);

  bool ret_val;
  ecma_property_t *prop_p = ecma_find_internal_property (obj_p, id);

  if (prop_p == NULL)
  {
    prop_p = ecma_create_internal_property (obj_p, id);

    ret_val = true;
  }
  else
  {
    ret_val = false;
  }

  JERRY_STATIC_ASSERT (sizeof (uint32_t) <= sizeof (prop_p->u.internal_property.value));

  if (sizeof (ecma_external_pointer_t) == sizeof (uint32_t))
  {
    prop_p->u.internal_property.value = (uint32_t) ptr_value;
  }
  else
  {
    ecma_external_pointer_t *handler_p = ecma_alloc_external_pointer ();
    *handler_p = ptr_value;

    ECMA_SET_NON_NULL_POINTER (prop_p->u.internal_property.value, handler_p);
  }

  return ret_val;
} /* ecma_create_external_pointer_property */
Exemple #18
0
/**
 * Create a property in an object and link it into
 * the object's properties' linked-list (at start of the list).
 *
 * @return pointer to newly created property
 */
static ecma_property_t *
ecma_create_property (ecma_object_t *object_p, /**< the object */
                      ecma_string_t *name_p, /**< property name */
                      uint8_t type_and_flags, /**< type and flags, see ecma_property_info_t */
                      ecma_property_value_t value) /**< property value */
{
  JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2);

  jmem_cpointer_t *property_list_head_p = &object_p->property_list_or_bound_object_cp;
  bool has_hashmap = false;

  if (*property_list_head_p != ECMA_NULL_POINTER)
  {
    /* If the first entry is a hashmap, it is skipped. */
    ecma_property_header_t *first_property_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
                                                                          *property_list_head_p);

    if (ECMA_PROPERTY_GET_TYPE (first_property_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP)
    {
      property_list_head_p = &first_property_p->next_property_cp;
      has_hashmap = true;
    }
  }

  if (*property_list_head_p != ECMA_NULL_POINTER)
  {
    /* If the first entry is free (deleted), it is reused. */
    ecma_property_header_t *first_property_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
                                                                          *property_list_head_p);

    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (first_property_p));

    if (first_property_p->types[0].type_and_flags == ECMA_PROPERTY_TYPE_DELETED)
    {
      first_property_p->types[0].type_and_flags = type_and_flags;

      ecma_property_pair_t *first_property_pair_p = (ecma_property_pair_t *) first_property_p;
      ECMA_SET_POINTER (first_property_pair_p->names_cp[0], name_p);

      ecma_property_t *property_p = first_property_p->types + 0;

      JERRY_ASSERT (ECMA_PROPERTY_VALUE_PTR (property_p) == first_property_pair_p->values + 0);

      first_property_pair_p->values[0] = value;

      /* The property must be fully initialized before ecma_property_hashmap_insert
       * is called, because the insert operation may reallocate the hashmap, and
       * that triggers garbage collection which scans all properties of all objects.
       * A not fully initialized but queued property may cause a crash. */

      if (has_hashmap && name_p != NULL)
      {
        ecma_property_hashmap_insert (object_p,
                                      name_p,
                                      first_property_pair_p,
                                      0);
      }

      return property_p;
    }
  }

  /* Otherwise we create a new property pair and use its second value. */
  ecma_property_pair_t *first_property_pair_p = ecma_alloc_property_pair ();

  /* Just copy the previous value (no need to decompress, compress). */
  first_property_pair_p->header.next_property_cp = *property_list_head_p;
  first_property_pair_p->header.types[0].type_and_flags = ECMA_PROPERTY_TYPE_DELETED;
  first_property_pair_p->header.types[1].type_and_flags = type_and_flags;
  first_property_pair_p->names_cp[0] = ECMA_NULL_POINTER;
  ECMA_SET_POINTER (first_property_pair_p->names_cp[1], name_p);

  ECMA_SET_NON_NULL_POINTER (*property_list_head_p, &first_property_pair_p->header);

  ecma_property_t *property_p = first_property_pair_p->header.types + 1;

  JERRY_ASSERT (ECMA_PROPERTY_VALUE_PTR (property_p) == first_property_pair_p->values + 1);

  first_property_pair_p->values[1] = value;

  /* See the comment before the other ecma_property_hashmap_insert above. */

  if (has_hashmap && name_p != NULL)
  {
    ecma_property_hashmap_insert (object_p,
                                  name_p,
                                  first_property_pair_p,
                                  1);
  }

  return property_p;
} /* ecma_create_property */
Exemple #19
0
/**
 * Insert an entry into LCache
 */
void
ecma_lcache_insert (ecma_object_t *object_p, /**< object */
                    ecma_string_t *prop_name_p, /**< property's name */
                    ecma_property_t *prop_p) /**< pointer to associated property or NULL
                                              *   (NULL indicates that the object doesn't have property
                                              *   with the name specified) */
{
  JERRY_ASSERT (object_p != NULL);
  JERRY_ASSERT (prop_name_p != NULL);

#ifndef CONFIG_ECMA_LCACHE_DISABLE
  prop_name_p = ecma_copy_or_ref_ecma_string (prop_name_p);

  lit_string_hash_t hash_key = ecma_string_hash (prop_name_p);

  if (prop_p != NULL)
  {
    if (unlikely (ecma_is_property_lcached (prop_p)))
    {
      int32_t entry_index;
      for (entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++)
      {
        if (ecma_lcache_hash_table[hash_key][entry_index].object_cp != ECMA_NULL_POINTER
            && ecma_lcache_hash_table[hash_key][entry_index].prop_p == prop_p)
        {
#ifndef JERRY_NDEBUG
          ecma_object_t *obj_in_entry_p;
          obj_in_entry_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t,
                                                      ecma_lcache_hash_table[hash_key][entry_index].object_cp);
          JERRY_ASSERT (obj_in_entry_p == object_p);
#endif /* !JERRY_NDEBUG */
          break;
        }
      }

      JERRY_ASSERT (entry_index != ECMA_LCACHE_HASH_ROW_LENGTH);
      ecma_lcache_invalidate_entry (&ecma_lcache_hash_table[hash_key][entry_index]);
    }

    JERRY_ASSERT (!ecma_is_property_lcached (prop_p));
    ecma_set_property_lcached (prop_p, true);
  }

  int32_t entry_index;
  for (entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++)
  {
    if (ecma_lcache_hash_table[hash_key][entry_index].object_cp == ECMA_NULL_POINTER)
    {
      break;
    }
  }

  if (entry_index == ECMA_LCACHE_HASH_ROW_LENGTH)
  {
    /* No empty entry was found, invalidating the whole row */
    for (uint32_t i = 0; i < ECMA_LCACHE_HASH_ROW_LENGTH; i++)
    {
      ecma_lcache_invalidate_entry (&ecma_lcache_hash_table[hash_key][i]);
    }

    entry_index = 0;
  }

  ecma_ref_object (object_p);
  ECMA_SET_NON_NULL_POINTER (ecma_lcache_hash_table[ hash_key ][ entry_index ].object_cp, object_p);
  ECMA_SET_NON_NULL_POINTER (ecma_lcache_hash_table[ hash_key ][ entry_index ].prop_name_cp, prop_name_p);
  ecma_lcache_hash_table[ hash_key ][ entry_index ].prop_p = prop_p;
#else /* CONFIG_ECMA_LCACHE_DISABLE */
  (void) prop_p;
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
} /* ecma_lcache_insert */
/**
 * The Function.prototype object's 'bind' routine
 *
 * See also:
 *          ECMA-262 v5, 15.3.4.5
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this argument */
                                             const ecma_value_t* arguments_list_p, /**< list of arguments */
                                             ecma_length_t arguments_number) /**< number of arguments */
{
  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

  /* 2. */
  if (!ecma_op_is_callable (this_arg))
  {
    ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
  }
  else
  {
    /* 4. 11. 18. */
    ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
    ecma_object_t *function_p = ecma_create_object (prototype_obj_p, true, ECMA_OBJECT_TYPE_BOUND_FUNCTION);

    ecma_deref_object (prototype_obj_p);

    /* 7. */
    ecma_property_t *target_function_prop_p;
    target_function_prop_p = ecma_create_internal_property (function_p,
                                                            ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION);

    ecma_object_t *this_arg_obj_p = ecma_get_object_from_value (this_arg);
    ECMA_SET_NON_NULL_POINTER (target_function_prop_p->u.internal_property.value, this_arg_obj_p);

    /* 8. */
    ecma_property_t *bound_this_prop_p;
    bound_this_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS);
    const ecma_length_t arg_count = arguments_number;

    if (arg_count > 0)
    {
      bound_this_prop_p->u.internal_property.value = ecma_copy_value (arguments_list_p[0], false);
    }
    else
    {
      bound_this_prop_p->u.internal_property.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
    }

    if (arg_count > 1)
    {
      ecma_collection_header_t *bound_args_collection_p;
      bound_args_collection_p = ecma_new_values_collection (&arguments_list_p[1], arg_count - 1, false);

      ecma_property_t *bound_args_prop_p;
      bound_args_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS);
      ECMA_SET_NON_NULL_POINTER (bound_args_prop_p->u.internal_property.value, bound_args_collection_p);
    }

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

    ecma_number_t *length_p = ecma_alloc_number ();
    ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);

    /* 15. */
    if (ecma_object_get_class_name (this_arg_obj_p) == LIT_MAGIC_STRING_FUNCTION_UL)
    {
      ecma_completion_value_t get_len_completion = ecma_op_object_get (this_arg_obj_p,
                                                                       magic_string_length_p);
      JERRY_ASSERT (ecma_is_completion_value_normal (get_len_completion));

      ecma_value_t len_value = ecma_get_completion_value_value (get_len_completion);
      JERRY_ASSERT (ecma_is_value_number (len_value));

      const ecma_length_t bound_arg_count = arg_count > 1 ? arg_count - 1 : 0;

      /* 15.a */
      *length_p = *ecma_get_number_from_value (len_value) - ecma_uint32_to_number (bound_arg_count);
      ecma_free_completion_value (get_len_completion);

      /* 15.b */
      if (ecma_number_is_negative (*length_p))
      {
        *length_p = ECMA_NUMBER_ZERO;
      }
    }
    else
    {
      /* 16. */
      *length_p = ECMA_NUMBER_ZERO;
    }

    /* 17. */
    ecma_completion_value_t completion = ecma_builtin_helper_def_prop (function_p,
                                                                       magic_string_length_p,
                                                                       ecma_make_number_value (length_p),
                                                                       false, /* Writable */
                                                                       false, /* Enumerable */
                                                                       false, /* Configurable */
                                                                       false); /* Failure handling */

    JERRY_ASSERT (ecma_is_completion_value_normal_true (completion)
                  || ecma_is_completion_value_normal_false (completion));

    ecma_deref_ecma_string (magic_string_length_p);
    ecma_dealloc_number (length_p);

    /* 19-21. */
    ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);

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

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

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

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

    ecma_string_t *magic_string_caller_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER);
    completion = ecma_op_object_define_own_property (function_p,
                                                     magic_string_caller_p,
                                                     &prop_desc,
                                                     false);

    JERRY_ASSERT (ecma_is_completion_value_normal_true (completion)
                  || ecma_is_completion_value_normal_false (completion));

    ecma_deref_ecma_string (magic_string_caller_p);

    ecma_string_t *magic_string_arguments_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
    completion = ecma_op_object_define_own_property (function_p,
                                                     magic_string_arguments_p,
                                                     &prop_desc,
                                                     false);

    JERRY_ASSERT (ecma_is_completion_value_normal_true (completion)
                  || ecma_is_completion_value_normal_false (completion));

    ecma_deref_ecma_string (magic_string_arguments_p);
    ecma_deref_object (thrower_p);

    /* 22. */
    ret_value = ecma_make_normal_completion_value (ecma_make_object_value (function_p));
  }

  return ret_value;
} /* ecma_builtin_function_prototype_object_bind */
/**
 * Append new value to ecma-values collection
 */
void
ecma_append_to_values_collection (ecma_collection_header_t *header_p, /**< collection's header */
                                  ecma_value_t v, /**< ecma-value to append */
                                  bool do_ref_if_object) /**< if the value is object value,
                                                              increase reference counter of the object */
{
  const size_t values_in_chunk = sizeof (ecma_collection_chunk_t::data) / sizeof (ecma_value_t);

  size_t values_number = header_p->unit_number;
  size_t pos_of_new_value_in_chunk = values_number % values_in_chunk;

  values_number++;

  if ((ecma_length_t) values_number == values_number)
  {
    header_p->unit_number = (ecma_length_t) values_number;
  }
  else
  {
    jerry_fatal (ERR_OUT_OF_MEMORY);
  }

  ecma_collection_chunk_t *chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t,
                                                       header_p->last_chunk_cp);

  if (pos_of_new_value_in_chunk == 0)
  {
    /* all chunks are currently filled with values */

    chunk_p = ecma_alloc_collection_chunk ();
    chunk_p->next_chunk_cp = ECMA_NULL_POINTER;

    if (header_p->last_chunk_cp == ECMA_NULL_POINTER)
    {
      JERRY_ASSERT (header_p->first_chunk_cp == ECMA_NULL_POINTER);

      ECMA_SET_NON_NULL_POINTER (header_p->first_chunk_cp, chunk_p);
    }
    else
    {
      ecma_collection_chunk_t *last_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
                                                                         header_p->last_chunk_cp);

      JERRY_ASSERT (last_chunk_p->next_chunk_cp == ECMA_NULL_POINTER);

      ECMA_SET_NON_NULL_POINTER (last_chunk_p->next_chunk_cp, chunk_p);
    }

    ECMA_SET_NON_NULL_POINTER (header_p->last_chunk_cp, chunk_p);
  }
  else
  {
    /* last chunk can be appended with the new value */
    JERRY_ASSERT (chunk_p != NULL);
  }

  ecma_value_t *values_p = (ecma_value_t *) chunk_p->data;

  JERRY_ASSERT ((uint8_t *) (values_p + pos_of_new_value_in_chunk + 1) <= (uint8_t *) (chunk_p + 1));

  values_p[pos_of_new_value_in_chunk] = ecma_copy_value (v, do_ref_if_object);
} /* ecma_append_to_values_collection */