Beispiel #1
0
/**
 * Delete the object's property.
 *
 * Warning: specified property must be owned by specified object.
 */
void
ecma_delete_property (ecma_object_t *object_p, /**< object */
                      ecma_property_t *prop_p) /**< property */
{
  ecma_property_header_t *cur_prop_p = ecma_get_property_list (object_p);
  ecma_property_header_t *prev_prop_p = NULL;

  while (true)
  {
    JERRY_ASSERT (cur_prop_p != NULL);
    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (cur_prop_p));

    ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) cur_prop_p;

    for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
    {
      if ((cur_prop_p->types + i) == prop_p)
      {
        ecma_string_t *name_p = ECMA_GET_POINTER (ecma_string_t, prop_pair_p->names_cp[i]);

        ecma_free_property (object_p, name_p, cur_prop_p->types + i);

        prop_pair_p->names_cp[i] = ECMA_NULL_POINTER;

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

        JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2);

        if (cur_prop_p->types[1 - i].type_and_flags != ECMA_PROPERTY_TYPE_DELETED)
        {
          /* The other property is still valid. */
          return;
        }

        JERRY_ASSERT (cur_prop_p->types[i].type_and_flags == ECMA_PROPERTY_TYPE_DELETED);

        if (prev_prop_p == NULL)
        {
          object_p->property_list_or_bound_object_cp = cur_prop_p->next_property_cp;
        }
        else
        {
          prev_prop_p->next_property_cp = cur_prop_p->next_property_cp;
        }

        ecma_dealloc_property_pair ((ecma_property_pair_t *) cur_prop_p);
        return;
      }
    }

    prev_prop_p = cur_prop_p;
    cur_prop_p = ECMA_GET_POINTER (ecma_property_header_t,
                                   cur_prop_p->next_property_cp);
  }
} /* ecma_delete_property */
Beispiel #2
0
/**
 * Get setter of named accessor property
 *
 * @return pointer to object - setter of the property
 */
ecma_object_t *
ecma_get_named_accessor_property_setter (const ecma_property_value_t *prop_value_p) /**< property value reference */
{
#ifdef JERRY_CPOINTER_32_BIT
  ecma_getter_setter_pointers_t *getter_setter_pair_p;
  getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t,
                                           prop_value_p->getter_setter_pair_cp);
  return ECMA_GET_POINTER (ecma_object_t, getter_setter_pair_p->setter_p);
#else /* !JERRY_CPOINTER_32_BIT */
  return ECMA_GET_POINTER (ecma_object_t, prop_value_p->getter_setter_pair.setter_p);
#endif /* JERRY_CPOINTER_32_BIT */
} /* ecma_get_named_accessor_property_setter */
Beispiel #3
0
/**
 * Find internal property in the object's property set.
 *
 * @return pointer to the property, if it is found,
 *         NULL - otherwise.
 */
ecma_property_t *
ecma_find_internal_property (ecma_object_t *object_p, /**< object descriptor */
                             ecma_internal_property_id_t property_id) /**< internal property identifier */
{
  JERRY_ASSERT (object_p != NULL);

  JERRY_ASSERT (property_id != ECMA_INTERNAL_PROPERTY_PROTOTYPE
                && property_id != ECMA_INTERNAL_PROPERTY_EXTENSIBLE);

  ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p);

  while (prop_iter_p != NULL)
  {
    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));

    if (ECMA_PROPERTY_GET_TYPE (&prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_INTERNAL
        && ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (prop_iter_p->types + 0) == property_id)
    {
      return prop_iter_p->types + 0;
    }

    if (ECMA_PROPERTY_GET_TYPE (&prop_iter_p->types[1]) == ECMA_PROPERTY_TYPE_INTERNAL
        && ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (prop_iter_p->types + 1) == property_id)
    {
      return prop_iter_p->types + 1;
    }

    prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
                                    prop_iter_p->next_property_cp);
  }

  return NULL;
} /* ecma_find_internal_property */
Beispiel #4
0
/**
 * Get next object in list of objects with same generation.
 */
static inline ecma_object_t *
ecma_gc_get_object_next (ecma_object_t *object_p) /**< object */
{
  JERRY_ASSERT (object_p != NULL);

  return ECMA_GET_POINTER (ecma_object_t, object_p->gc_next_cp);
} /* ecma_gc_get_object_next */
Beispiel #5
0
/**
 * Get setter of named accessor property
 *
 * @return pointer to object - setter of the property
 */
ecma_object_t *
ecma_get_named_accessor_property_setter (const ecma_property_t *prop_p) /**< named accessor property */
{
  JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);

  return ECMA_GET_POINTER (ecma_object_t, ECMA_PROPERTY_VALUE_PTR (prop_p)->getter_setter_pair.setter_p);
} /* ecma_get_named_accessor_property_setter */
Beispiel #6
0
/**
 * Check that
 */
static void
ecma_assert_object_contains_the_property (const ecma_object_t *object_p, /**< ecma-object */
                                          const ecma_property_t *prop_p) /**< ecma-property */
{
#ifndef JERRY_NDEBUG
  ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p);

  while (prop_iter_p != NULL)
  {
    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));

    ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;

    for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
    {
      if ((prop_pair_p->header.types + i) == prop_p)
      {
        return;
      }
    }

    prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
                                    prop_iter_p->next_property_cp);
  }

  JERRY_UNREACHABLE ();

#else /* JERRY_NDEBUG */
  (void) object_p;
  (void) prop_p;
#endif /* JERRY_NDEBUG */
} /* ecma_assert_object_contains_the_property */
/**
 * Free the collection of ecma values.
 */
void
ecma_free_values_collection (ecma_collection_header_t *header_p, /**< collection's header */
                             bool do_deref_if_object) /**< if the value is object value,
                                                           decrement reference counter of the object */
{
  JERRY_ASSERT (header_p != NULL);

  const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t);

  ecma_collection_chunk_t *chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t,
                                                       header_p->first_chunk_cp);
  ecma_length_t value_index = 0;

  while (chunk_p != NULL)
  {
    JERRY_ASSERT (value_index < header_p->unit_number);

    ecma_value_t *cur_value_buf_iter_p = (ecma_value_t *) chunk_p->data;
    ecma_value_t *cur_value_buf_end_p = cur_value_buf_iter_p + values_in_chunk;

    while (cur_value_buf_iter_p != cur_value_buf_end_p
           && value_index < header_p->unit_number)
    {
      JERRY_ASSERT (cur_value_buf_iter_p < cur_value_buf_end_p);

      if (do_deref_if_object)
      {
        ecma_free_value (*cur_value_buf_iter_p);
      }
      else
      {
        ecma_free_value_if_not_object (*cur_value_buf_iter_p);
      }

      cur_value_buf_iter_p++;
      value_index++;
    }

    ecma_collection_chunk_t *next_chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t,
                                                              chunk_p->next_chunk_cp);
    ecma_dealloc_collection_chunk (chunk_p);
    chunk_p = next_chunk_p;
  }

  ecma_dealloc_collection_header (header_p);
} /* ecma_free_values_collection */
Beispiel #8
0
/**
 * Find named data property or named access property in specified object.
 *
 * @return pointer to the property, if it is found,
 *         NULL - otherwise.
 */
ecma_property_t *
ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in */
                          ecma_string_t *name_p) /**< property's name */
{
  JERRY_ASSERT (obj_p != NULL);
  JERRY_ASSERT (name_p != NULL);

  ecma_property_t *property_p;

  if (ecma_lcache_lookup (obj_p, name_p, &property_p))
  {
    return property_p;
  }

  property_p = NULL;

  ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_p);

  while (prop_iter_p != NULL)
  {
    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));

    ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;

    JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2);

    if (prop_pair_p->names_cp[0] != ECMA_NULL_POINTER)
    {
      ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
                                                                  prop_pair_p->names_cp[0]);

      if (ecma_compare_ecma_strings (name_p, property_name_p))
      {
        property_p = prop_iter_p->types + 0;
        break;
      }
    }

    if (prop_pair_p->names_cp[1] != ECMA_NULL_POINTER)
    {
      ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
                                                                  prop_pair_p->names_cp[1]);

      if (ecma_compare_ecma_strings (name_p, property_name_p))
      {
        property_p = prop_iter_p->types + 1;
        break;
      }
    }

    prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
                                    prop_iter_p->next_property_cp);
  }

  ecma_lcache_insert (obj_p, name_p, property_p);

  return property_p;
} /* ecma_find_named_property */
Beispiel #9
0
/**
 * Get outer reference of lexical environment.
 */
inline ecma_object_t *__attr_pure___
ecma_get_lex_env_outer_reference (const ecma_object_t *object_p) /**< lexical environment */
{
  JERRY_ASSERT (object_p != NULL);
  JERRY_ASSERT (ecma_is_lexical_environment (object_p));

  return ECMA_GET_POINTER (ecma_object_t,
                           object_p->prototype_or_outer_reference_cp);
} /* ecma_get_lex_env_outer_reference */
Beispiel #10
0
/**
 * Mark objects as visited starting from specified object as root
 */
void
ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
{
  JERRY_ASSERT (object_p != NULL);
  JERRY_ASSERT (ecma_gc_is_object_visited (object_p));

  bool traverse_properties = true;

  if (ecma_is_lexical_environment (object_p))
  {
    ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p);
    if (lex_env_p != NULL)
    {
      ecma_gc_set_object_visited (lex_env_p, true);
    }

    if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
    {
      ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p);
      ecma_gc_set_object_visited (binding_object_p, true);

      traverse_properties = false;
    }
  }
  else
  {
    ecma_object_t *proto_p = ecma_get_object_prototype (object_p);
    if (proto_p != NULL)
    {
      ecma_gc_set_object_visited (proto_p, true);
    }
  }

  if (traverse_properties)
  {
    ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p);

    while (prop_iter_p != NULL)
    {
      JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));

      if (prop_iter_p->types[0].type_and_flags != ECMA_PROPERTY_TYPE_DELETED)
      {
        ecma_gc_mark_property (prop_iter_p->types + 0);
      }

      if (prop_iter_p->types[1].type_and_flags != ECMA_PROPERTY_TYPE_DELETED)
      {
        ecma_gc_mark_property (prop_iter_p->types + 1);
      }

      prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
                                      prop_iter_p->next_property_cp);
    }
  }
} /* ecma_gc_mark */
Beispiel #11
0
/**
 * Get object's/lexical environment's property list.
 *
 * See also:
 *          ecma_op_object_get_property_names
 */
inline ecma_property_header_t *__attr_pure___
ecma_get_property_list (const ecma_object_t *object_p) /**< object or lexical environment */
{
  JERRY_ASSERT (object_p != NULL);
  JERRY_ASSERT (!ecma_is_lexical_environment (object_p)
                || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);

  return ECMA_GET_POINTER (ecma_property_header_t,
                           object_p->property_list_or_bound_object_cp);
} /* ecma_get_property_list */
Beispiel #12
0
/**
 * Check whether the object contains a property
 */
static void
ecma_assert_object_contains_the_property (const ecma_object_t *object_p, /**< ecma-object */
                                          const ecma_property_value_t *prop_value_p, /**< property value */
                                          ecma_property_types_t type) /**< expected property type */
{
#ifndef JERRY_NDEBUG
  ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p);

  JERRY_ASSERT (prop_iter_p != NULL);

  if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
  {
    prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
                                    prop_iter_p->next_property_cp);
  }

  while (prop_iter_p != NULL)
  {
    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));

    ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;

    for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
    {
      if ((prop_pair_p->values + i) == prop_value_p)
      {
        JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_pair_p->header.types[i]) == type);
        return;
      }
    }

    prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
                                    prop_iter_p->next_property_cp);
  }

  JERRY_UNREACHABLE ();

#else /* JERRY_NDEBUG */
  JERRY_UNUSED (object_p);
  JERRY_UNUSED (prop_value_p);
  JERRY_UNUSED (type);
#endif /* !JERRY_NDEBUG */
} /* ecma_assert_object_contains_the_property */
Beispiel #13
0
/**
 * Free property values and change their type to deleted.
 */
void
ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to */
                    jmem_cpointer_t name_cp, /**< name of the property or ECMA_NULL_POINTER */
                    ecma_property_t *property_p) /**< property */
{
  JERRY_ASSERT (object_p != NULL && property_p != NULL);

  switch (ECMA_PROPERTY_GET_TYPE (*property_p))
  {
    case ECMA_PROPERTY_TYPE_NAMEDDATA:
    {
      if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_STRING_CONTAINER_MAGIC_STRING)
      {
        if (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE
            || name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER)
        {
          ecma_free_native_pointer (property_p);
          break;
        }
      }

      ecma_free_value_if_not_object (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
      break;
    }
    case ECMA_PROPERTY_TYPE_NAMEDACCESSOR:
    {
#ifdef JERRY_CPOINTER_32_BIT
      ecma_getter_setter_pointers_t *getter_setter_pair_p;
      getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t,
                                               ECMA_PROPERTY_VALUE_PTR (property_p)->getter_setter_pair_cp);
      jmem_pools_free (getter_setter_pair_p, sizeof (ecma_getter_setter_pointers_t));
#endif /* JERRY_CPOINTER_32_BIT */
      break;
    }
    default:
    {
      JERRY_UNREACHABLE ();
      return;
    }
  }

  if (ecma_is_property_lcached (property_p))
  {
    ecma_lcache_invalidate (object_p, name_cp, property_p);
  }

  if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_PROPERTY_NAME_TYPE_STRING)
  {
    ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp);
    ecma_deref_ecma_string (prop_name_p);
  }

  *property_p = ECMA_PROPERTY_TYPE_DELETED;
} /* ecma_free_property */
/**
 * Move collection iterator to next element if there is any.
 *
 * @return true - if iterator moved,
 *         false - otherwise (current element is last element in the collection)
 */
bool
ecma_collection_iterator_next (ecma_collection_iterator_t *iterator_p) /**< context of iterator */
{
  if (iterator_p->header_p == NULL
      || unlikely (iterator_p->header_p->unit_number == 0))
  {
    return false;
  }

  const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t);

  if (iterator_p->current_value_p == NULL)
  {
    JERRY_ASSERT (iterator_p->current_index == 0);

    ecma_collection_chunk_t *first_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
                                                                        iterator_p->header_p->first_chunk_cp);

    iterator_p->next_chunk_cp = first_chunk_p->next_chunk_cp;
    iterator_p->current_value_p = (ecma_value_t *) &first_chunk_p->data;
    iterator_p->current_chunk_end_p = (iterator_p->current_value_p + values_in_chunk);
  }
  else
  {
    if (iterator_p->current_index + 1 == iterator_p->header_p->unit_number)
    {
      return false;
    }

    JERRY_ASSERT (iterator_p->current_index + 1 < iterator_p->header_p->unit_number);

    iterator_p->current_index++;
    iterator_p->current_value_p++;
  }

  if (iterator_p->current_value_p == iterator_p->current_chunk_end_p)
  {
    ecma_collection_chunk_t *next_chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t,
                                                              iterator_p->next_chunk_cp);
    JERRY_ASSERT (next_chunk_p != NULL);

    iterator_p->next_chunk_cp = next_chunk_p->next_chunk_cp;
    iterator_p->current_value_p = (ecma_value_t *) &next_chunk_p->data;
    iterator_p->current_chunk_end_p = iterator_p->current_value_p + values_in_chunk;
  }
  else
  {
    JERRY_ASSERT (iterator_p->current_value_p < iterator_p->current_chunk_end_p);
  }

  return true;
} /* ecma_collection_iterator_next */
Beispiel #15
0
/**
 * Get next object in list of objects with same generation.
 */
static ecma_object_t*
ecma_gc_get_object_next (ecma_object_t *object_p) /**< object */
{
    JERRY_ASSERT (object_p != NULL);

    JERRY_ASSERT (sizeof (uintptr_t) * JERRY_BITSINBYTE >= ECMA_OBJECT_GC_NEXT_CP_WIDTH);
    uintptr_t next_cp = (uintptr_t) jrt_extract_bit_field (object_p->container,
                        ECMA_OBJECT_GC_NEXT_CP_POS,
                        ECMA_OBJECT_GC_NEXT_CP_WIDTH);

    return ECMA_GET_POINTER (ecma_object_t,
                             next_cp);
} /* ecma_gc_get_object_next */
/**
 * Helper function to merge argument lists
 *
 * See also:
 *          ECMA-262 v5, 15.3.4.5.1 step 4
 *          ECMA-262 v5, 15.3.4.5.2 step 4
 *
 * Used by:
 *         - [[Call]] implementation for Function objects.
 *         - [[Construct]] implementation for Function objects.
 *
 * @return ecma_value_t* - pointer to the merged argument list.
 */
static ecma_value_t*
ecma_function_bind_merge_arg_lists (ecma_object_t *func_obj_p, /**< Function object */
                                    const ecma_value_t *arguments_list_p, /**< arguments list */
                                    ecma_length_t arguments_list_len, /**< length of arguments list */
                                    ecma_length_t *total_args_count) /**< length of the merged argument list */
{
  ecma_value_t *arg_list_p;
  ecma_length_t bound_args_count = 0;

  ecma_property_t *bound_args_prop_p;
  bound_args_prop_p = ecma_find_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS);

  if (bound_args_prop_p != NULL)
  {
    ecma_collection_header_t *bound_arg_list_p = ECMA_GET_POINTER (ecma_collection_header_t,
                                                                   bound_args_prop_p->u.internal_property.value);

    ecma_collection_iterator_t bound_args_iterator;
    ecma_collection_iterator_init (&bound_args_iterator, bound_arg_list_p);

    bound_args_count = bound_arg_list_p->unit_number;

    *total_args_count = bound_args_count + arguments_list_len;

    const size_t arg_list_size = (size_t) *total_args_count * sizeof (ecma_value_t);
    arg_list_p = static_cast <ecma_value_t *> (mem_heap_alloc_block (arg_list_size, MEM_HEAP_ALLOC_SHORT_TERM));

    for (ecma_length_t i = 0; i < bound_args_count; i++)
    {
      bool is_moved = ecma_collection_iterator_next (&bound_args_iterator);
      JERRY_ASSERT (is_moved);

      arg_list_p[i] = *bound_args_iterator.current_value_p;
    }
  }
  else
  {
    *total_args_count = arguments_list_len;

    const size_t arg_list_size = (size_t) *total_args_count * sizeof (ecma_value_t);
    arg_list_p = static_cast <ecma_value_t *> (mem_heap_alloc_block (arg_list_size, MEM_HEAP_ALLOC_SHORT_TERM));
  }

  for (ecma_length_t i = 0; i < arguments_list_len; i++)
  {
    arg_list_p[i + bound_args_count] = arguments_list_p[i];
  }

  return arg_list_p;
} /* ecma_function_bind_merge_arg_lists */
Beispiel #17
0
/**
 * Set setter of named accessor property
 */
void
ecma_set_named_accessor_property_setter (ecma_object_t *object_p, /**< the property's container */
                                         ecma_property_value_t *prop_value_p, /**< property value reference */
                                         ecma_object_t *setter_p) /**< setter object */
{
  ecma_assert_object_contains_the_property (object_p, prop_value_p, ECMA_PROPERTY_TYPE_NAMEDACCESSOR);

#ifdef JERRY_CPOINTER_32_BIT
  ecma_getter_setter_pointers_t *getter_setter_pair_p;
  getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t,
                                           prop_value_p->getter_setter_pair_cp);
  ECMA_SET_POINTER (getter_setter_pair_p->setter_p, setter_p);
#else /* !JERRY_CPOINTER_32_BIT */
  ECMA_SET_POINTER (prop_value_p->getter_setter_pair.setter_p, setter_p);
#endif /* JERRY_CPOINTER_32_BIT */
} /* ecma_set_named_accessor_property_setter */
Beispiel #18
0
/**
 * Free specified object
 */
void
ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */
{
    JERRY_ASSERT (object_p != NULL
                  && !ecma_gc_is_object_visited (object_p)
                  && ecma_gc_get_object_refs (object_p) == 0);

    if (!ecma_is_lexical_environment (object_p))
    {
        /* if the object provides free callback, invoke it with handle stored in the object */

        ecma_external_pointer_t freecb_p;
        ecma_external_pointer_t native_p;

        bool is_retrieved = ecma_get_external_pointer_value (object_p,
                            ECMA_INTERNAL_PROPERTY_FREE_CALLBACK,
                            &freecb_p);
        if (is_retrieved)
        {
            is_retrieved = ecma_get_external_pointer_value (object_p,
                           ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE,
                           &native_p);
            JERRY_ASSERT (is_retrieved);

            jerry_dispatch_object_free_callback (freecb_p, native_p);
        }
    }

    if (!ecma_is_lexical_environment (object_p) ||
            ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND)
    {
        for (ecma_property_t *property = ecma_get_property_list (object_p), *next_property_p;
                property != NULL;
                property = next_property_p)
        {
            next_property_p = ECMA_GET_POINTER (ecma_property_t,
                                                property->next_property_p);

            ecma_free_property (object_p, property);
        }
    }

    JERRY_ASSERT (ecma_gc_objects_number > 0);
    ecma_gc_objects_number--;

    ecma_dealloc_object (object_p);
} /* ecma_gc_sweep */
/**
 * Lookup property in the LCache
 *
 * @return true - if (object, property name) pair is registered in LCache,
 *         false - probably, not registered.
 */
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);

      if (ecma_compare_ecma_strings_equal_hashes (prop_name_p, entry_prop_name_p))
      {
        ecma_property_t *prop_p = ECMA_GET_POINTER (ecma_property_t, ecma_lcache_hash_table[hash_key][i].prop_cp);
        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 */
Beispiel #20
0
/**
 * Free the internal property and values it references.
 */
static void
ecma_free_internal_property (ecma_property_t *property_p) /**< the property */
{
  JERRY_ASSERT (property_p != NULL && ECMA_PROPERTY_GET_TYPE (property_p) == ECMA_PROPERTY_TYPE_INTERNAL);

  uint32_t property_value = ECMA_PROPERTY_VALUE_PTR (property_p)->value;

  switch (ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (property_p))
  {
    case ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES: /* a collection */
    case ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES: /* a collection */
    {
      ecma_free_values_collection (ECMA_GET_NON_NULL_POINTER (ecma_collection_header_t,
                                                              property_value),
                                   true);

      break;
    }

    case ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE: /* compressed pointer to a ecma_string_t */
    {
      ecma_string_t *str_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
                                                        property_value);
      ecma_deref_ecma_string (str_p);

      break;
    }

    case ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE: /* pointer to a ecma_number_t */
    {
      ecma_number_t *num_p = ECMA_GET_NON_NULL_POINTER (ecma_number_t,
                                                        property_value);
      ecma_dealloc_number (num_p);

      break;
    }

    case ECMA_INTERNAL_PROPERTY_NATIVE_CODE: /* an external pointer */
    case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */
    case ECMA_INTERNAL_PROPERTY_FREE_CALLBACK: /* an external pointer */
    {
      ecma_free_external_pointer_in_property (property_p);

      break;
    }

    case ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE: /* a simple boolean value */
    case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */
    case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */
    case ECMA_INTERNAL_PROPERTY_PROTOTYPE: /* the property's value is located in ecma_object_t */
    case ECMA_INTERNAL_PROPERTY_EXTENSIBLE: /* the property's value is located in ecma_object_t */
    case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */
    case ECMA_INTERNAL_PROPERTY_BUILT_IN_ID: /* an integer */
    case ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_DESC: /* an integer */
    case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */
    case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_0_31: /* an integer (bit-mask) */
    case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_32_63: /* an integer (bit-mask) */
    case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION:
    {
      break;
    }

    case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS:
    {
      ecma_free_value_if_not_object (property_value);
      break;
    }

    case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS:
    {
      if (property_value != ECMA_NULL_POINTER)
      {
        ecma_free_values_collection (ECMA_GET_NON_NULL_POINTER (ecma_collection_header_t, property_value),
                                     false);
      }

      break;
    }

    case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type,
                                         * but number of the real internal property types */
    {
      JERRY_UNREACHABLE ();
      break;
    }

    case ECMA_INTERNAL_PROPERTY_CODE_BYTECODE: /* compressed pointer to a bytecode array */
    {
      ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, property_value));
      break;
    }

    case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE: /* compressed pointer to a regexp bytecode array */
    {
      ecma_compiled_code_t *bytecode_p = ECMA_GET_POINTER (ecma_compiled_code_t, property_value);

      if (bytecode_p != NULL)
      {
        ecma_bytecode_deref (bytecode_p);
      }
      break;
    }
  }
} /* ecma_free_internal_property */
Beispiel #21
0
/**
 * Mark objects as visited starting from specified object as root
 */
void
ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
{
    JERRY_ASSERT (object_p != NULL);
    JERRY_ASSERT (ecma_gc_is_object_visited (object_p));

    bool traverse_properties = true;

    if (ecma_is_lexical_environment (object_p))
    {
        ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p);
        if (lex_env_p != NULL)
        {
            ecma_gc_set_object_visited (lex_env_p, true);
        }

        if (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND)
        {
            ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p);
            ecma_gc_set_object_visited (binding_object_p, true);

            traverse_properties = false;
        }
    }
    else
    {
        ecma_object_t *proto_p = ecma_get_object_prototype (object_p);
        if (proto_p != NULL)
        {
            ecma_gc_set_object_visited (proto_p, true);
        }
    }

    if (traverse_properties)
    {
        for (ecma_property_t *property_p = ecma_get_property_list (object_p), *next_property_p;
                property_p != NULL;
                property_p = next_property_p)
        {
            next_property_p = ECMA_GET_POINTER (ecma_property_t,
                                                property_p->next_property_p);

            switch ((ecma_property_type_t) property_p->type)
            {
            case ECMA_PROPERTY_NAMEDDATA:
            {
                ecma_value_t value = ecma_get_named_data_property_value (property_p);

                if (ecma_is_value_object (value))
                {
                    ecma_object_t *value_obj_p = ecma_get_object_from_value (value);

                    ecma_gc_set_object_visited (value_obj_p, true);
                }

                break;
            }

            case ECMA_PROPERTY_NAMEDACCESSOR:
            {
                ecma_object_t *getter_obj_p = ecma_get_named_accessor_property_getter (property_p);
                ecma_object_t *setter_obj_p = ecma_get_named_accessor_property_setter (property_p);

                if (getter_obj_p != NULL)
                {
                    ecma_gc_set_object_visited (getter_obj_p, true);
                }

                if (setter_obj_p != NULL)
                {
                    ecma_gc_set_object_visited (setter_obj_p, true);
                }

                break;
            }

            case ECMA_PROPERTY_INTERNAL:
            {
                ecma_internal_property_id_t property_id = (ecma_internal_property_id_t) property_p->u.internal_property.type;
                uint32_t property_value = property_p->u.internal_property.value;

                switch (property_id)
                {
                case ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES: /* a collection of ecma-values */
                case ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES: /* a collection of ecma-values */
                {
                    JERRY_UNIMPLEMENTED ("Indexed array storage is not implemented yet.");
                }

                case ECMA_INTERNAL_PROPERTY_PROTOTYPE: /* the property's value is located in ecma_object_t
                                                    (see above in the routine) */
                case ECMA_INTERNAL_PROPERTY_EXTENSIBLE: /* the property's value is located in ecma_object_t
                                                     (see above in the routine) */
                case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type,
                                             * but number of the real internal property types */
                {
                    JERRY_UNREACHABLE ();
                }

                case ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS: /* a collection of strings */
                case ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE: /* compressed pointer to a ecma_string_t */
                case ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE: /* compressed pointer to a ecma_number_t */
                case ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE: /* a simple boolean value */
                case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */
                case ECMA_INTERNAL_PROPERTY_CODE_BYTECODE: /* compressed pointer to a bytecode array */
                case ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET: /* an integer */
                case ECMA_INTERNAL_PROPERTY_NATIVE_CODE: /* an external pointer */
                case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */
                case ECMA_INTERNAL_PROPERTY_FREE_CALLBACK: /* an object's native free callback */
                case ECMA_INTERNAL_PROPERTY_BUILT_IN_ID: /* an integer */
                case ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_DESC: /* an integer */
                case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */
                case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_0_31: /* an integer (bit-mask) */
                case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_32_63: /* an integer (bit-mask) */
                case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE:
                case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION:
                case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS:
                case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS:
                {
                    break;
                }

                case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */
                case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */
                {
                    ecma_object_t *obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, property_value);

                    ecma_gc_set_object_visited (obj_p, true);

                    break;
                }
                }

                break;
            }
            }
        }
    }
} /* ecma_gc_mark */
/**
 * 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 */
/**
 * The Object.keys and Object.getOwnPropertyName routine's common part.
 *
 * See also:
 *          ECMA-262 v5, 15.2.3.4 steps 2-5
 *          ECMA-262 v5, 15.2.3.14 steps 3-6
 *
 * @return completion value - Array of property names.
 *         Returned value must be freed with ecma_free_completion_value.
 */
ecma_completion_value_t
ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /** < object */
                                           bool only_enumerable_properties) /** < list enumerable properties? */
{
  JERRY_ASSERT (obj_p != NULL);

  ecma_completion_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
  JERRY_ASSERT (ecma_is_completion_value_normal (new_array));
  ecma_object_t *new_array_p = ecma_get_object_from_completion_value (new_array);

  uint32_t index = 0;

  for (ecma_property_t *property_p = ecma_get_property_list (obj_p);
       property_p != NULL;
       property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p))
  {
    ecma_string_t *property_name_p;

    if (property_p->type == ECMA_PROPERTY_NAMEDDATA)
    {
      property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
                                                   property_p->u.named_data_property.name_p);
    }
    else if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR)
    {
      property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
                                                   property_p->u.named_accessor_property.name_p);
    }
    else
    {
      continue;
    }

    if (only_enumerable_properties && !ecma_is_property_enumerable (property_p))
    {
      continue;
    }

    JERRY_ASSERT (property_name_p != NULL);

    ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);

    ecma_property_descriptor_t item_prop_desc = ecma_make_empty_property_descriptor ();
    {
      item_prop_desc.is_value_defined = true;
      item_prop_desc.value = ecma_make_string_value (property_name_p);

      item_prop_desc.is_writable_defined = true;
      item_prop_desc.is_writable = true;

      item_prop_desc.is_enumerable_defined = true;
      item_prop_desc.is_enumerable = true;

      item_prop_desc.is_configurable_defined = true;
      item_prop_desc.is_configurable = true;
    }

    ecma_completion_value_t completion = ecma_op_object_define_own_property (new_array_p,
                                                                             index_string_p,
                                                                             &item_prop_desc,
                                                                             false);

    JERRY_ASSERT (ecma_is_completion_value_normal_true (completion));

    ecma_free_completion_value (completion);
    ecma_deref_ecma_string (index_string_p);

    index++;
  }

  return new_array;
} /* ecma_builtin_helper_object_get_properties */
Beispiel #24
0
/**
 * Free specified object
 */
void
ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */
{
  JERRY_ASSERT (object_p != NULL
                && !ecma_gc_is_object_visited (object_p)
                && object_p->type_flags_refs < ECMA_OBJECT_REF_ONE);

  if (!ecma_is_lexical_environment (object_p))
  {
    /* if the object provides free callback, invoke it with handle stored in the object */

    ecma_external_pointer_t freecb_p;
    ecma_external_pointer_t native_p;

    bool is_retrieved = ecma_get_external_pointer_value (object_p,
                                                         ECMA_INTERNAL_PROPERTY_FREE_CALLBACK,
                                                         &freecb_p);

    if (is_retrieved && ((jerry_object_free_callback_t) freecb_p) != NULL)
    {
      is_retrieved = ecma_get_external_pointer_value (object_p,
                                                      ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE,
                                                      &native_p);
      JERRY_ASSERT (is_retrieved);

      jerry_dispatch_object_free_callback (freecb_p, native_p);
    }
  }

  if (!ecma_is_lexical_environment (object_p)
      || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
  {
    ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p);

    if (prop_iter_p != NULL
        && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_HASHMAP)
    {
      ecma_property_hashmap_free (object_p);
      prop_iter_p = ecma_get_property_list (object_p);
    }

    while (prop_iter_p != NULL)
    {
      JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));

      /* Both cannot be deleted. */
      JERRY_ASSERT (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED
                    || prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED);

      ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;

      for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
      {
        if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED)
        {
          ecma_string_t *name_p = ECMA_GET_POINTER (ecma_string_t, prop_pair_p->names_cp[i]);

          ecma_free_property (object_p, name_p, prop_iter_p->types + i);

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

      /* Both must be deleted. */
      JERRY_ASSERT (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_DELETED
                    && prop_iter_p->types[1] == ECMA_PROPERTY_TYPE_DELETED);

      prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
                                      prop_iter_p->next_property_cp);

      ecma_dealloc_property_pair (prop_pair_p);
    }
  }

  JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_number) > 0);
  JERRY_CONTEXT (ecma_gc_objects_number)--;

  if (!ecma_is_lexical_environment (object_p))
  {
    if (ecma_get_object_is_builtin (object_p)
        || ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
    {
      ecma_dealloc_extended_object ((ecma_extended_object_t *) object_p);
      return;
    }

    if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION)
    {
      /* Function with byte-code (not a built-in function). */
      ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;

      ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t,
                                                            ext_func_p->u.function.bytecode_cp));

      ecma_dealloc_extended_object (ext_func_p);
      return;
    }
  }

  ecma_dealloc_object (object_p);
} /* ecma_gc_sweep */
Beispiel #25
0
/**
 * Find named data property or named access property in specified object.
 *
 * @return pointer to the property, if it is found,
 *         NULL - otherwise.
 */
ecma_property_t *
ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in */
                          ecma_string_t *name_p) /**< property's name */
{
  JERRY_ASSERT (obj_p != NULL);
  JERRY_ASSERT (name_p != NULL);

  ecma_property_t *property_p = ecma_lcache_lookup (obj_p, name_p);

  if (property_p != NULL)
  {
    return property_p;
  }

  ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_p);

#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
  if (prop_iter_p != NULL
      && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP)
  {
    ecma_string_t *property_real_name_p;
    property_p = ecma_property_hashmap_find ((ecma_property_hashmap_t *) prop_iter_p,
                                             name_p,
                                             &property_real_name_p);

    if (property_p != NULL
        && !ecma_is_property_lcached (property_p))
    {
      ecma_lcache_insert (obj_p, property_real_name_p, property_p);
    }

    return property_p;
  }
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */

  property_p = NULL;
  ecma_string_t *property_name_p = NULL;

  uint32_t steps = 0;

  while (prop_iter_p != NULL)
  {
    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));

    ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;

    JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2);

    if (prop_pair_p->names_cp[0] != ECMA_NULL_POINTER)
    {
      property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
                                                   prop_pair_p->names_cp[0]);

      if (ecma_compare_ecma_strings (name_p, property_name_p))
      {
        property_p = prop_iter_p->types + 0;
        break;
      }
    }

    if (prop_pair_p->names_cp[1] != ECMA_NULL_POINTER)
    {
      property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
                                                   prop_pair_p->names_cp[1]);

      if (ecma_compare_ecma_strings (name_p, property_name_p))
      {
        property_p = prop_iter_p->types + 1;
        break;
      }
    }

    steps++;

    prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
                                    prop_iter_p->next_property_cp);
  }

  if (steps > (ECMA_PROPERTY_HASMAP_MINIMUM_SIZE / 4))
  {
    ecma_property_hashmap_create (obj_p);
  }

  if (property_p != NULL
      && !ecma_is_property_lcached (property_p))
  {
    ecma_lcache_insert (obj_p, property_name_p, property_p);
  }

  return property_p;
} /* ecma_find_named_property */
Beispiel #26
0
/**
 * Mark objects as visited starting from specified object as root
 */
void
ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
{
  JERRY_ASSERT (object_p != NULL);
  JERRY_ASSERT (ecma_gc_is_object_visited (object_p));

  bool traverse_properties = true;

  if (ecma_is_lexical_environment (object_p))
  {
    ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p);
    if (lex_env_p != NULL)
    {
      ecma_gc_set_object_visited (lex_env_p, true);
    }

    if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
    {
      ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p);
      ecma_gc_set_object_visited (binding_object_p, true);

      traverse_properties = false;
    }
  }
  else
  {
    ecma_object_t *proto_p = ecma_get_object_prototype (object_p);
    if (proto_p != NULL)
    {
      ecma_gc_set_object_visited (proto_p, true);
    }

    if (!ecma_get_object_is_builtin (object_p)
        && ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION)
    {
      ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;

      ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
                                                                ext_func_p->u.function.scope_cp);

      ecma_gc_set_object_visited (scope_p, true);
    }
  }

  if (traverse_properties)
  {
    ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p);

    if (prop_iter_p != NULL
        && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_HASHMAP)
    {
      prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
                                      prop_iter_p->next_property_cp);
    }

    while (prop_iter_p != NULL)
    {
      JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));

      if (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED)
      {
        ecma_gc_mark_property (prop_iter_p->types + 0);
      }

      if (prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED)
      {
        ecma_gc_mark_property (prop_iter_p->types + 1);
      }

      prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
                                      prop_iter_p->next_property_cp);
    }
  }
} /* ecma_gc_mark */
Beispiel #27
0
/**
 * Enumerate properties and construct collection with their
 * names for further iteration in for-in opcode handler.
 *
 * See also:
 *          ECMA-262 v5, 12.6.4
 *
 * @return header of constructed strings collection (should be freed with ecma_free_values_collection),
 *         or NULL - if there are no properties to enumerate in for-in.
 */
static ecma_collection_header_t *
vm_helper_for_in_enumerate_properties_names (ecma_object_t *obj_p) /**< starting object - result of ToObject
                                                                    *   conversion (ECMA-262 v5, 12.6.4, step 4) */
{
  const size_t bitmap_row_size = sizeof (uint32_t) * JERRY_BITSINBYTE;
  uint32_t names_hashes_bitmap[(1u << LIT_STRING_HASH_BITS) / bitmap_row_size];

  memset (names_hashes_bitmap, 0, sizeof (names_hashes_bitmap));

  ecma_length_t all_properties_count = 0;

  /* First pass: counting properties */
  for (ecma_object_t *prototype_chain_iter_p = obj_p;
       prototype_chain_iter_p != NULL;
       prototype_chain_iter_p = ecma_get_object_prototype (prototype_chain_iter_p))
  {
    for (ecma_property_t *prop_iter_p = ecma_get_property_list (prototype_chain_iter_p);
         prop_iter_p != NULL;
         prop_iter_p = ECMA_GET_POINTER (ecma_property_t, prop_iter_p->next_property_p))
    {
      if (prop_iter_p->type == ECMA_PROPERTY_NAMEDDATA
          || prop_iter_p->type == ECMA_PROPERTY_NAMEDACCESSOR)
      {
        all_properties_count++;
      }
      else
      {
        JERRY_ASSERT (prop_iter_p->type == ECMA_PROPERTY_INTERNAL);
      }
    }
  }

  if (all_properties_count == 0)
  {
    return NULL;
  }

  ecma_collection_header_t *ret_p = NULL;

  /* Second pass: collecting properties names */
  MEM_DEFINE_LOCAL_ARRAY (names_p, all_properties_count, ecma_string_t*);

  ecma_length_t enumerated_properties_count = 0;
  ecma_length_t non_enumerated_properties_count = 0;

  for (ecma_object_t *prototype_chain_iter_p = obj_p;
       prototype_chain_iter_p != NULL;
       prototype_chain_iter_p = ecma_get_object_prototype (prototype_chain_iter_p))
  {
    for (ecma_property_t *prop_iter_p = ecma_get_property_list (prototype_chain_iter_p);
         prop_iter_p != NULL;
         prop_iter_p = ECMA_GET_POINTER (ecma_property_t, prop_iter_p->next_property_p))
    {
      if (prop_iter_p->type == ECMA_PROPERTY_NAMEDDATA
          || prop_iter_p->type == ECMA_PROPERTY_NAMEDACCESSOR)
      {
        bool is_enumerated;

        ecma_string_t *prop_name_p;

        if (prop_iter_p->type == ECMA_PROPERTY_NAMEDDATA)
        {
          prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_iter_p->u.named_data_property.name_p);
        }
        else
        {
          prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_iter_p->u.named_accessor_property.name_p);
        }

        lit_string_hash_t hash = prop_name_p->hash;
        uint32_t bitmap_row = hash / bitmap_row_size;
        uint32_t bitmap_column = hash % bitmap_row_size;

        if (ecma_is_property_enumerable (prop_iter_p))
        {
          if ((names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) == 0)
          {
            /* no name with the hash occured during the iteration session */
            is_enumerated = true;
          }
          else
          {
            /* name with same hash already occured */
            bool is_equal_found = false;

            for (uint32_t index = 0;
                 !is_equal_found && index < enumerated_properties_count;
                 index++)
            {
              if (ecma_compare_ecma_strings (prop_name_p,
                                             names_p[index]))
              {
                is_equal_found = true;
              }
            }

            for (uint32_t index = 0;
                 !is_equal_found && index < non_enumerated_properties_count;
                 index++)
            {
              if (ecma_compare_ecma_strings (prop_name_p,
                                             names_p[all_properties_count - index - 1]))
              {
                is_equal_found = true;
              }
            }

            is_enumerated = !is_equal_found;
          }
        }
        else
        {
          is_enumerated = false;
        }

        names_hashes_bitmap[bitmap_row] |= (1u << bitmap_column);

        if (is_enumerated)
        {
          names_p[enumerated_properties_count++] = prop_name_p;
        }
        else
        {
          names_p[all_properties_count - non_enumerated_properties_count++ - 1] = prop_name_p;
        }

        JERRY_ASSERT (enumerated_properties_count + non_enumerated_properties_count <= all_properties_count);
      }
      else
      {
        JERRY_ASSERT (prop_iter_p->type == ECMA_PROPERTY_INTERNAL);
      }
    }
  }

  if (enumerated_properties_count != 0)
  {
    ret_p = ecma_new_strings_collection (names_p, enumerated_properties_count);
  }

  MEM_FINALIZE_LOCAL_ARRAY (names_p);

  return ret_p;
} /* vm_helper_for_in_enumerate_properties_names */
/**
 * RegExp helper function to start the recursive matching algorithm
 * and create the result Array object
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value
 */
ecma_completion_value_t
ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */
                         ecma_value_t input_string, /**< input string */
                         bool ignore_global) /**< ignore global flag */
{
  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

  JERRY_ASSERT (ecma_is_value_object (regexp_value));
  JERRY_ASSERT (ecma_is_value_string (input_string));

  ecma_object_t *regexp_object_p = ecma_get_object_from_value (regexp_value);

  JERRY_ASSERT (ecma_object_get_class_name (regexp_object_p) == LIT_MAGIC_STRING_REGEXP_UL);

  ecma_property_t *bytecode_prop_p = ecma_get_internal_property (regexp_object_p,
                                                                 ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE);
  re_bytecode_t *bc_p = ECMA_GET_POINTER (re_bytecode_t, bytecode_prop_p->u.internal_property.value);

  ecma_string_t *input_string_p = ecma_get_string_from_value (input_string);
  lit_utf8_size_t input_string_size = ecma_string_get_size (input_string_p);

  MEM_DEFINE_LOCAL_ARRAY (input_utf8_buffer_p, input_string_size, lit_utf8_byte_t);

  ecma_string_to_utf8_string (input_string_p, input_utf8_buffer_p, (ssize_t) input_string_size);
  lit_utf8_iterator_t iterator = lit_utf8_iterator_create (input_utf8_buffer_p, input_string_size);

  re_matcher_ctx_t re_ctx;
  re_ctx.input_start_p = iterator.buf_p;
  re_ctx.input_end_p = iterator.buf_p + iterator.buf_size;

  /* 1. Read bytecode header and init regexp matcher context. */
  re_ctx.flags = (uint8_t) re_get_value (&bc_p);

  if (ignore_global)
  {
    re_ctx.flags &= (uint8_t) ~RE_FLAG_GLOBAL;
  }

  JERRY_DDLOG ("Exec with flags [global: %d, ignoreCase: %d, multiline: %d]\n",
               re_ctx.flags & RE_FLAG_GLOBAL,
               re_ctx.flags & RE_FLAG_IGNORE_CASE,
               re_ctx.flags & RE_FLAG_MULTILINE);

  re_ctx.num_of_captures = re_get_value (&bc_p);
  JERRY_ASSERT (re_ctx.num_of_captures % 2 == 0);
  re_ctx.num_of_non_captures = re_get_value (&bc_p);

  /* We create an invalid iterator, that will be used to identify unused result values. */
  lit_utf8_iterator_t unused_iter = lit_utf8_iterator_create (NULL, 0);
  unused_iter.buf_p = (lit_utf8_byte_t *) 1;

  MEM_DEFINE_LOCAL_ARRAY (saved_p, re_ctx.num_of_captures + re_ctx.num_of_non_captures, lit_utf8_iterator_t);

  for (uint32_t i = 0; i < re_ctx.num_of_captures + re_ctx.num_of_non_captures; i++)
  {
    saved_p[i] = unused_iter;
  }
  re_ctx.saved_p = saved_p;

  uint32_t num_of_iter_length = (re_ctx.num_of_captures / 2) + (re_ctx.num_of_non_captures - 1);
  MEM_DEFINE_LOCAL_ARRAY (num_of_iter_p, num_of_iter_length, uint32_t);

  for (uint32_t i = 0; i < num_of_iter_length; i++)
  {
    num_of_iter_p[i] = 0u;
  }

  bool is_match = false;
  re_ctx.num_of_iterations_p = num_of_iter_p;
  int32_t index = 0;
  ecma_length_t input_str_len = lit_utf8_string_length (iterator.buf_p, iterator.buf_size);

  if (iterator.buf_p && (re_ctx.flags & RE_FLAG_GLOBAL))
  {
    ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL);
    ecma_property_t *lastindex_prop_p = ecma_op_object_get_property (regexp_object_p, magic_str_p);

    ECMA_OP_TO_NUMBER_TRY_CATCH (lastindex_num, lastindex_prop_p->u.named_data_property.value, ret_value)
    index = ecma_number_to_int32 (lastindex_num);

    JERRY_ASSERT (iterator.buf_pos.offset == 0 && !iterator.buf_pos.is_non_bmp_middle);
    if (!lit_utf8_iterator_is_eos (&iterator)
        && index <= (int32_t) input_str_len
        && index > 0)
    {
      lit_utf8_iterator_advance (&iterator, (ecma_length_t) index);
    }
    ECMA_OP_TO_NUMBER_FINALIZE (lastindex_num);
    ecma_deref_ecma_string (magic_str_p);
  }

  /* 2. Try to match */
  lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0);

  while (ecma_is_completion_value_empty (ret_value))
  {
    if (index < 0 || index > (int32_t) input_str_len)
    {
      if (re_ctx.flags & RE_FLAG_GLOBAL)
      {
        ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL);
        ecma_number_t *lastindex_num_p = ecma_alloc_number ();
        *lastindex_num_p = ECMA_NUMBER_ZERO;
        ecma_op_object_put (regexp_object_p, magic_str_p, ecma_make_number_value (lastindex_num_p), true);
        ecma_dealloc_number (lastindex_num_p);
        ecma_deref_ecma_string (magic_str_p);
      }

      is_match = false;
      break;
    }
    else
    {
      ECMA_TRY_CATCH (match_value, re_match_regexp (&re_ctx, bc_p, iterator, &sub_iter), ret_value);

      if (ecma_is_value_true (match_value))
      {
        is_match = true;
        break;
      }

      if (!lit_utf8_iterator_is_eos (&iterator))
      {
        lit_utf8_iterator_advance (&iterator, 1);
      }
      index++;

      ECMA_FINALIZE (match_value);
    }
  }

  if (iterator.buf_p && (re_ctx.flags & RE_FLAG_GLOBAL))
  {
    ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL);
    ecma_number_t *lastindex_num_p = ecma_alloc_number ();
    *lastindex_num_p = sub_iter.buf_pos.offset;
    ecma_op_object_put (regexp_object_p, magic_str_p, ecma_make_number_value (lastindex_num_p), true);
    ecma_dealloc_number (lastindex_num_p);
    ecma_deref_ecma_string (magic_str_p);
  }

  /* 3. Fill the result array or return with 'undefiend' */
  if (ecma_is_completion_value_empty (ret_value))
  {
    if (is_match)
    {
      ecma_completion_value_t result_array = ecma_op_create_array_object (0, 0, false);
      ecma_object_t *result_array_obj_p = ecma_get_object_from_completion_value (result_array);

      ecma_string_t *input_str_p = ecma_new_ecma_string_from_utf8 (iterator.buf_p, iterator.buf_size);
      re_set_result_array_properties (result_array_obj_p, input_str_p, re_ctx.num_of_captures / 2, index);
      ecma_deref_ecma_string (input_str_p);

      for (uint32_t i = 0; i < re_ctx.num_of_captures; i += 2)
      {
        ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (i / 2);

        /* Note: 'iter_p->buf_p == NULL' means the input is empty string */
        if ((re_ctx.saved_p[i].buf_p != unused_iter.buf_p && re_ctx.saved_p[i + 1].buf_p != unused_iter.buf_p)
            && re_ctx.saved_p[i + 1].buf_pos.offset >= re_ctx.saved_p[i].buf_pos.offset)
        {
          ecma_length_t capture_str_len;
          capture_str_len = (ecma_length_t) re_ctx.saved_p[i + 1].buf_pos.offset - re_ctx.saved_p[i].buf_pos.offset;
          ecma_string_t *capture_str_p;

          if (capture_str_len > 0)
          {
            const lit_utf8_byte_t *utf8_str_p = re_ctx.saved_p[i].buf_p + re_ctx.saved_p[i].buf_pos.offset;
            capture_str_p = ecma_new_ecma_string_from_utf8 (utf8_str_p, capture_str_len);
          }
          else
          {
            capture_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
          }
          ecma_op_object_put (result_array_obj_p, index_str_p, ecma_make_string_value (capture_str_p), true);
          ecma_deref_ecma_string (capture_str_p);
        }
        else
        {
          ecma_op_object_put (result_array_obj_p,
                              index_str_p,
                              ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED),
                              true);
        }
        ecma_deref_ecma_string (index_str_p);
      }
      ret_value = result_array;
    }
    else
    {
      ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL));
    }
  }

  MEM_FINALIZE_LOCAL_ARRAY (num_of_iter_p);
  MEM_FINALIZE_LOCAL_ARRAY (saved_p);
  MEM_FINALIZE_LOCAL_ARRAY (input_utf8_buffer_p);

  return ret_value;
} /* ecma_regexp_exec_helper */
/**
 * The RegExp.prototype object's 'compile' routine
 *
 * See also:
 *          ECMA-262 v5, B.2.5.1
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument */
                                       ecma_value_t pattern_arg, /**< pattern or RegExp object */
                                       ecma_value_t flags_arg) /**< flags */
{
  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
  ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg);

  if (ecma_object_get_class_name (this_obj_p) != LIT_MAGIC_STRING_REGEXP_UL)
  {
    /* Compile can only be called on RegExp objects. */
    ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
  }
  else
  {
    ecma_string_t *pattern_string_p = NULL;
    uint16_t flags = 0;

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

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

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

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

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

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

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

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

        ecma_deref_ecma_string (magic_string_p);

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

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

        re_compiled_code_t *old_bc_p = ECMA_GET_POINTER (re_compiled_code_t,
                                                         bc_prop_p->u.internal_property.value);
        if (old_bc_p != NULL)
        {
          /* Free the old bytecode */
          ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p);
        }

        ECMA_SET_POINTER (bc_prop_p->u.internal_property.value, new_bc_p);

        re_initialize_props (this_obj_p, pattern_string_p, flags);

        ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED));
      }
    }
    else
    {
      /* Get source string. */
      if (!ecma_is_value_undefined (pattern_arg))
      {
        ECMA_TRY_CATCH (regexp_str_value,
                        ecma_op_to_string (pattern_arg),
                        ret_value);

        if (ecma_string_get_length (ecma_get_string_from_value (regexp_str_value)) == 0)
        {
          pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
        }
        else
        {
          pattern_string_p = ecma_copy_or_ref_ecma_string (ecma_get_string_from_value (regexp_str_value));
        }

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

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

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

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

        re_compiled_code_t *old_bc_p = ECMA_GET_POINTER (re_compiled_code_t,
                                                         bc_prop_p->u.internal_property.value);

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

        ECMA_SET_POINTER (bc_prop_p->u.internal_property.value, new_bc_p);
        re_initialize_props (this_obj_p, pattern_string_p, flags);
        ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED));

        ECMA_FINALIZE (bc_dummy);
      }

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

  return ret_value;
} /* ecma_builtin_regexp_prototype_compile */
/**
 * Setup variables for arguments listed in formal parameter list,
 * and, if necessary, Arguments object with 'arguments' binding.
 *
 * See also:
 *          Declaration binding instantiation (ECMA-262 v5, 10.5), block 4 and 7
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value
 */
static ecma_completion_value_t
ecma_function_call_setup_args_variables (ecma_object_t *func_obj_p, /**< Function object */
                                         ecma_object_t *env_p, /**< lexical environment */
                                         const ecma_value_t *arguments_list_p, /**< arguments list */
                                         ecma_length_t arguments_list_len, /**< length of argument list */
                                         bool is_strict, /**< flag indicating strict mode */
                                         bool do_instantiate_arguments_object) /**< flag indicating whether
                                                                                *   Arguments object should be
                                                                                *   instantiated */
{
  ecma_property_t *formal_parameters_prop_p = ecma_get_internal_property (func_obj_p,
                                                                          ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS);
  ecma_collection_header_t *formal_parameters_p;
  formal_parameters_p = ECMA_GET_POINTER (ecma_collection_header_t,
                                          formal_parameters_prop_p->u.internal_property.value);

  if (formal_parameters_p != NULL)
  {
    ecma_length_t formal_parameters_count = formal_parameters_p->unit_number;

    ecma_collection_iterator_t formal_params_iterator;
    ecma_collection_iterator_init (&formal_params_iterator, formal_parameters_p);

    /*
     * Formal parameter list is stored in reversed order
     *
     * Although, specification defines ascending order of formal parameters list enumeration,
     * implementation enumerates the parameters in descending order.
     *
     * In the case, redundant SetMutableBinding invocation could be avoided.
     */
    for (ssize_t n = (ssize_t) formal_parameters_count - 1;
         n >= 0;
         n--)
    {
      ecma_value_t v;
      if (n >= (ssize_t) arguments_list_len)
      {
        v = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
      }
      else
      {
        v = arguments_list_p[n];
      }

      bool is_moved = ecma_collection_iterator_next (&formal_params_iterator);
      JERRY_ASSERT (is_moved);

      ecma_value_t formal_parameter_name_value = *formal_params_iterator.current_value_p;
      ecma_string_t *formal_parameter_name_string_p = ecma_get_string_from_value (formal_parameter_name_value);

      bool arg_already_declared = ecma_op_has_binding (env_p, formal_parameter_name_string_p);
      if (!arg_already_declared)
      {
        ecma_completion_value_t completion = ecma_op_create_mutable_binding (env_p,
                                                                             formal_parameter_name_string_p,
                                                                             false);
        if (ecma_is_completion_value_throw (completion))
        {
          return completion;
        }

        JERRY_ASSERT (ecma_is_completion_value_empty (completion));

        completion = ecma_op_set_mutable_binding (env_p,
                                                  formal_parameter_name_string_p,
                                                  v,
                                                  is_strict);

        if (ecma_is_completion_value_throw (completion))
        {
          return completion;
        }

        JERRY_ASSERT (ecma_is_completion_value_empty (completion));
      }
    }
  }

  if (do_instantiate_arguments_object)
  {
    /*
     * According to ECMA-262 v5, 10.5, the Arguments object should be instantiated
     * after instantiating declared functions, and only if there is no binding named 'arguments'
     * by that time.
     *
     * However, we can setup Arguments object and 'arguments' binding here, because:
     *  - instantiation of Arguments object itself doesn't have any side effects;
     *  - if 'arguments' is name of a declared function in current scope,
     *    value of the binding would be overwritten, execution would proceed in correct state.
     *  - declaration of function, named 'arguments', is considered to be unrecommended (and so, rare) case,
     *    so instantiation of Arguments object here, in general, is supposed to not affect resource consumption
     *    significantly.
     */

    ecma_string_t *arguments_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);

    bool binding_already_declared = ecma_op_has_binding (env_p, arguments_string_p);

    if (!binding_already_declared)
    {
      ecma_object_t *args_obj_p = ecma_op_create_arguments_object (func_obj_p,
                                                                   env_p,
                                                                   formal_parameters_p,
                                                                   arguments_list_p,
                                                                   arguments_list_len,
                                                                   is_strict);

      if (is_strict)
      {
        ecma_op_create_immutable_binding (env_p, arguments_string_p);
        ecma_op_initialize_immutable_binding (env_p, arguments_string_p, ecma_make_object_value (args_obj_p));
      }
      else
      {
        ecma_completion_value_t completion = ecma_op_create_mutable_binding (env_p,
                                                                             arguments_string_p,
                                                                             false);
        JERRY_ASSERT (ecma_is_completion_value_empty (completion));

        completion = ecma_op_set_mutable_binding (env_p,
                                                  arguments_string_p,
                                                  ecma_make_object_value (args_obj_p),
                                                  false);
        JERRY_ASSERT (ecma_is_completion_value_empty (completion));
      }

      ecma_deref_object (args_obj_p);
    }

    ecma_deref_ecma_string (arguments_string_p);
  }

  return ecma_make_empty_completion_value ();
} /* ecma_function_call_setup_args_variables */