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

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

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

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

  // 4., 5.
  if (prototype_p != NULL)
  {
    return ecma_op_object_get_property (prototype_p, property_name_p);
  }
  else
  {
    return NULL;
  }
} /* ecma_op_general_object_get_property */
/**
 * 'in' opcode handler.
 *
 * See also: ECMA-262 v5, 11.8.7
 *
 * @return ecma value
 *         returned value must be freed with ecma_free_value.
 */
ecma_value_t
opfunc_in (ecma_value_t left_value, /**< left value */
           ecma_value_t right_value) /**< right value */
{
  ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  if (!ecma_is_value_object (right_value))
  {
    ret_value = ecma_raise_type_error (ECMA_ERR_MSG (""));
  }
  else
  {
    ECMA_TRY_CATCH (str_left_value, ecma_op_to_string (left_value), ret_value);

    ecma_string_t *left_value_prop_name_p = ecma_get_string_from_value (str_left_value);
    ecma_object_t *right_value_obj_p = ecma_get_object_from_value (right_value);

    if (ecma_op_object_get_property (right_value_obj_p, left_value_prop_name_p) != NULL)
    {
      ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
    }
    else
    {
      ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE);
    }

    ECMA_FINALIZE (str_left_value);
  }

  return ret_value;
} /* opfunc_in */
Beispiel #3
0
/**
 * Resolve value corresponding to reference.
 *
 * @return value of the reference
 */
ecma_value_t
ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical environment */
                                 ecma_string_t *name_p, /**< identifier's name */
                                 bool is_strict) /**< strict mode */
{
  JERRY_ASSERT (lex_env_p != NULL);

  while (lex_env_p != NULL)
  {
    if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
    {
      ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);

      if (property_p != NULL)
      {
        ecma_value_t prop_value = ecma_get_named_data_property_value (property_p);

        /* is the binding mutable? */
        if (unlikely (!ecma_is_property_writable (property_p)
                      && ecma_is_value_empty (prop_value)))
        {
          /* unitialized mutable binding */
          if (is_strict)
          {
            return ecma_raise_reference_error (ECMA_ERR_MSG (""));
          }
          else
          {
            return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
          }
        }
        return ecma_fast_copy_value (prop_value);
      }
    }
    else
    {
      JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND
                    || ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);

      ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);

      ecma_property_t *property_p = ecma_op_object_get_property (binding_obj_p, name_p);

      if (property_p != NULL)
      {
        return ecma_op_object_get (binding_obj_p, name_p);
      }
    }

    lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
  }

  return ecma_raise_reference_error (ECMA_ERR_MSG (""));
} /* ecma_op_resolve_reference_value */
Beispiel #4
0
/**
 * GetBindingValue operation.
 *
 * See also: ECMA-262 v5, 10.2.1
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
 */
ecma_value_t
ecma_op_get_binding_value (ecma_object_t *lex_env_p, /**< lexical environment */
                           ecma_string_t *name_p, /**< argument N */
                           bool is_strict) /**< argument S */
{
  JERRY_ASSERT (lex_env_p != NULL
                && ecma_is_lexical_environment (lex_env_p));
  JERRY_ASSERT (name_p != NULL);

  if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
  {
    ecma_property_t *property_p = ecma_get_named_data_property (lex_env_p, name_p);

    ecma_value_t prop_value = ecma_get_named_data_property_value (property_p);

    /* is the binding mutable? */
    if (!ecma_is_property_writable (property_p)
        && ecma_is_value_empty (prop_value))
    {
      /* unitialized immutable binding */
      if (is_strict)
      {
        return ecma_raise_reference_error ("");
      }
      else
      {
        return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
      }
    }

    return ecma_copy_value (prop_value, true);
  }
  else
  {
    JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND);

    ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);

    if (ecma_op_object_get_property (binding_obj_p, name_p) == NULL)
    {
      if (is_strict)
      {
        return ecma_raise_reference_error ("");
      }
      else
      {
        return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
      }
    }

    return ecma_op_object_get (binding_obj_p, name_p);
  }
} /* ecma_op_get_binding_value */
/**
 * [[Get]] ecma general object's operation
 *
 * See also:
 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
 *          ECMA-262 v5, 8.12.3
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value
 */
ecma_completion_value_t
ecma_op_general_object_get (ecma_object_t *obj_p, /**< the object */
                            ecma_string_t *property_name_p) /**< property name */
{
  JERRY_ASSERT (obj_p != NULL
                && !ecma_is_lexical_environment (obj_p));
  JERRY_ASSERT (property_name_p != NULL);

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

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

  // 3.
  if (prop_p->type == ECMA_PROPERTY_NAMEDDATA)
  {
    return ecma_make_normal_completion_value (ecma_copy_value (ecma_get_named_data_property_value (prop_p),
                                                               true));
  }
  else
  {
    // 4.
    ecma_object_t *getter_p = ecma_get_named_accessor_property_getter (prop_p);

    // 5.
    if (getter_p == NULL)
    {
      return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED);
    }
    else
    {
      return ecma_op_function_call (getter_p,
                                    ecma_make_object_value (obj_p),
                                    NULL);
    }
  }

  JERRY_UNREACHABLE ();
} /* ecma_op_general_object_get */
Beispiel #6
0
/**
 * HasBinding operation.
 *
 * See also: ECMA-262 v5, 10.2.1
 *
 * @return true / false
 */
bool
ecma_op_has_binding (ecma_object_t *lex_env_p, /**< lexical environment */
                     ecma_string_t *name_p) /**< argument N */
{
  JERRY_ASSERT (lex_env_p != NULL
                && ecma_is_lexical_environment (lex_env_p));

  if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
  {
    ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);

    return (property_p != NULL);
  }
  else
  {
    JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND);

    ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);

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

  JERRY_ASSERT (!is_unresolvable_reference);
  JERRY_ASSERT (is_property_reference);

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

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

    ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

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

    ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

    ECMA_FINALIZE (put_ret_value);

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

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

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

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

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

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

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

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

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

        ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

        ECMA_FINALIZE (call_ret);
      }
    }

    ECMA_FINALIZE (obj_base);

    return ret_value;
  }
} /* ecma_op_put_value_object_base */
/**
 * GetBindingValue operation.
 *
 * See also: ECMA-262 v5, 10.2.1
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
ecma_completion_value_t
ecma_op_get_binding_value (ecma_object_t *lex_env_p, /**< lexical environment */
                           ecma_string_t *name_p, /**< argument N */
                           bool is_strict) /**< argument S */
{
  JERRY_ASSERT (lex_env_p != NULL
                && ecma_is_lexical_environment (lex_env_p));
  JERRY_ASSERT (name_p != NULL);

  if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
  {
#ifndef JERRY_NDEBUG
# ifdef CONFIG_ECMA_COMPACT_PROFILE
    bool is_equal = false;

    ecma_string_t *arguments_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
    if (ecma_compare_ecma_strings (name_p, arguments_magic_string_p))
    {
      is_equal = true;
    }
    ecma_deref_ecma_string (arguments_magic_string_p);

    JERRY_ASSERT (!is_equal);

    if (is_equal)
    {
      return ecma_make_throw_obj_completion_value (ecma_builtin_get (ECMA_BUILTIN_ID_COMPACT_PROFILE_ERROR));
    }
# endif /* CONFIG_ECMA_COMPACT_PROFILE */
#endif /* !JERRY_NDEBUG */

    ecma_property_t *property_p = ecma_get_named_data_property (lex_env_p, name_p);

    ecma_value_t prop_value = ecma_get_named_data_property_value (property_p);

    /* is the binding mutable? */
    if (!ecma_is_property_writable (property_p)
        && ecma_is_value_empty (prop_value))
    {
      /* unitialized immutable binding */
      if (is_strict)
      {
        return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_REFERENCE));
      }
      else
      {
        return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED);
      }
    }

    return ecma_make_normal_completion_value (ecma_copy_value (prop_value, true));
  }
  else
  {
    JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND);

    ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);

    if (ecma_op_object_get_property (binding_obj_p, name_p) == NULL)
    {
      if (is_strict)
      {
        return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_REFERENCE));
      }
      else
      {
        return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED);
      }
    }

    return ecma_op_object_get (binding_obj_p, name_p);
  }
} /* ecma_op_get_binding_value */
Beispiel #9
0
/**
 * 'for-in' opcode handler
 *
 * See also:
 *          ECMA-262 v5, 12.6.4
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value
 */
ecma_completion_value_t
opfunc_for_in (vm_instr_t instr, /**< instruction */
               vm_frame_ctx_t *int_data_p) /**< interpreter context */
{
  const idx_t expr_idx = instr.data.for_in.expr;
  const idx_t block_end_oc_idx_1 = instr.data.for_in.oc_idx_1;
  const idx_t block_end_oc_idx_2 = instr.data.for_in.oc_idx_2;
  const vm_instr_counter_t for_in_end_oc = (vm_instr_counter_t) (
    vm_calc_instr_counter_from_idx_idx (block_end_oc_idx_1,
                                        block_end_oc_idx_2) + int_data_p->pos);

  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

  /* 1., 2. */
  ECMA_TRY_CATCH (expr_value,
                  get_variable_value (int_data_p,
                                      expr_idx,
                                      false),
                  ret_value);

  int_data_p->pos++;

  vm_instr_t meta_instr = vm_get_instr (int_data_p->instrs_p, for_in_end_oc);
  JERRY_ASSERT (meta_instr.op_idx == VM_OP_META);
  JERRY_ASSERT (meta_instr.data.meta.type == OPCODE_META_TYPE_END_FOR_IN);

  /* 3. */
  if (!ecma_is_value_undefined (expr_value)
      && !ecma_is_value_null (expr_value))
  {
    /* 4. */
    ECMA_TRY_CATCH (obj_expr_value,
                    ecma_op_to_object (expr_value),
                    ret_value);

    ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value);

    ecma_collection_iterator_t names_iterator;
    ecma_collection_header_t *names_p = vm_helper_for_in_enumerate_properties_names (obj_p);

    if (names_p != NULL)
    {
      ecma_collection_iterator_init (&names_iterator, names_p);

      const vm_instr_counter_t for_in_body_begin_oc = int_data_p->pos;
      const vm_instr_counter_t for_in_body_end_oc = for_in_end_oc;

      while (ecma_collection_iterator_next (&names_iterator))
      {
        ecma_value_t name_value = *names_iterator.current_value_p;

        ecma_string_t *name_p = ecma_get_string_from_value (name_value);

        if (ecma_op_object_get_property (obj_p, name_p) != NULL)
        {
          ecma_completion_value_t completion = set_variable_value (int_data_p,
                                                                   int_data_p->pos,
                                                                   OPCODE_REG_SPECIAL_FOR_IN_PROPERTY_NAME,
                                                                   name_value);
          JERRY_ASSERT (ecma_is_completion_value_empty (completion));

          vm_run_scope_t run_scope_for_in = { for_in_body_begin_oc, for_in_body_end_oc };

          ecma_completion_value_t for_in_body_completion = vm_loop (int_data_p, &run_scope_for_in);
          if (ecma_is_completion_value_empty (for_in_body_completion))
          {
            JERRY_ASSERT (int_data_p->pos == for_in_body_end_oc);

            int_data_p->pos = for_in_body_begin_oc;
          }
          else
          {
            JERRY_ASSERT (ecma_is_completion_value_throw (for_in_body_completion)
                          || ecma_is_completion_value_return (for_in_body_completion)
                          || ecma_is_completion_value_jump (for_in_body_completion));
            JERRY_ASSERT (int_data_p->pos <= for_in_body_end_oc);

            ret_value = for_in_body_completion;
            break;
          }
        }
      }

      ecma_free_values_collection (names_p, true);
    }

    ECMA_FINALIZE (obj_expr_value);
  }

  int_data_p->pos = (vm_instr_counter_t) (for_in_end_oc + 1u);

  ECMA_FINALIZE (expr_value);

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

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

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

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

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

      JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA);

      return ecma_is_property_writable (prop_p);
    }
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

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

    ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE);

    ECMA_FINALIZE (call_ret);

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

  JERRY_UNREACHABLE ();
} /* ecma_op_general_object_put */
Beispiel #13
0
/**
 * ToPropertyDescriptor operation.
 *
 * See also:
 *          ECMA-262 v5, 8.10.5
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value
 */
ecma_value_t
ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */
                                ecma_property_descriptor_t *out_prop_desc_p) /**< [out] filled property descriptor
                                                                                  if return value is normal
                                                                                  empty completion value */
{
  ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  // 1.
  if (!ecma_is_value_object (obj_value))
  {
    ret_value = ecma_raise_type_error (ECMA_ERR_MSG (""));
  }
  else
  {
    ecma_object_t *obj_p = ecma_get_object_from_value (obj_value);

    // 2.
    ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();

    // 3.
    ecma_string_t *enumerable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ENUMERABLE);

    if (ecma_op_object_get_property (obj_p, enumerable_magic_string_p) != NULL)
    {
      ECMA_TRY_CATCH (enumerable_prop_value,
                      ecma_op_object_get (obj_p, enumerable_magic_string_p),
                      ret_value);

      prop_desc.is_enumerable_defined = true;
      prop_desc.is_enumerable = ecma_op_to_boolean (enumerable_prop_value);

      ECMA_FINALIZE (enumerable_prop_value);
    }

    ecma_deref_ecma_string (enumerable_magic_string_p);

    if (!ecma_is_value_error (ret_value))
    {
      JERRY_ASSERT (ecma_is_value_empty (ret_value));

      // 4.
      ecma_string_t *configurable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONFIGURABLE);

      if (ecma_op_object_get_property (obj_p, configurable_magic_string_p) != NULL)
      {
        ECMA_TRY_CATCH (configurable_prop_value,
                        ecma_op_object_get (obj_p, configurable_magic_string_p),
                        ret_value);

        prop_desc.is_configurable_defined = true;
        prop_desc.is_configurable = ecma_op_to_boolean (configurable_prop_value);

        ECMA_FINALIZE (configurable_prop_value);
      }

      ecma_deref_ecma_string (configurable_magic_string_p);
    }

    if (!ecma_is_value_error (ret_value))
    {
      JERRY_ASSERT (ecma_is_value_empty (ret_value));

      // 5.
      ecma_string_t *value_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_VALUE);

      if (ecma_op_object_get_property (obj_p, value_magic_string_p) != NULL)
      {
        ECMA_TRY_CATCH (value_prop_value,
                        ecma_op_object_get (obj_p, value_magic_string_p),
                        ret_value);

        prop_desc.is_value_defined = true;
        prop_desc.value = ecma_copy_value (value_prop_value);

        ECMA_FINALIZE (value_prop_value);
      }

      ecma_deref_ecma_string (value_magic_string_p);
    }

    if (!ecma_is_value_error (ret_value))
    {
      JERRY_ASSERT (ecma_is_value_empty (ret_value));

      // 6.
      ecma_string_t *writable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_WRITABLE);

      if (ecma_op_object_get_property (obj_p, writable_magic_string_p) != NULL)
      {
        ECMA_TRY_CATCH (writable_prop_value,
                        ecma_op_object_get (obj_p, writable_magic_string_p),
                        ret_value);

        prop_desc.is_writable_defined = true;
        prop_desc.is_writable = ecma_op_to_boolean (writable_prop_value);

        ECMA_FINALIZE (writable_prop_value);
      }

      ecma_deref_ecma_string (writable_magic_string_p);
    }

    if (!ecma_is_value_error (ret_value))
    {
      JERRY_ASSERT (ecma_is_value_empty (ret_value));

      // 7.
      ecma_string_t *get_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GET);

      if (ecma_op_object_get_property (obj_p, get_magic_string_p) != NULL)
      {
        ECMA_TRY_CATCH (get_prop_value,
                        ecma_op_object_get (obj_p, get_magic_string_p),
                        ret_value);

        if (!ecma_op_is_callable (get_prop_value)
            && !ecma_is_value_undefined (get_prop_value))
        {
          ret_value = ecma_raise_type_error (ECMA_ERR_MSG (""));
        }
        else
        {
          prop_desc.is_get_defined = true;

          if (ecma_is_value_undefined (get_prop_value))
          {
            prop_desc.get_p = NULL;
          }
          else
          {
            JERRY_ASSERT (ecma_is_value_object (get_prop_value));

            ecma_object_t *get_p = ecma_get_object_from_value (get_prop_value);
            ecma_ref_object (get_p);

            prop_desc.get_p = get_p;
          }
        }

        ECMA_FINALIZE (get_prop_value);
      }

      ecma_deref_ecma_string (get_magic_string_p);
    }

    if (!ecma_is_value_error (ret_value))
    {
      JERRY_ASSERT (ecma_is_value_empty (ret_value));

      // 8.

      ecma_string_t *set_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SET);

      if (ecma_op_object_get_property (obj_p, set_magic_string_p) != NULL)
      {
        ECMA_TRY_CATCH (set_prop_value,
                        ecma_op_object_get (obj_p, set_magic_string_p),
                        ret_value);

        if (!ecma_op_is_callable (set_prop_value)
            && !ecma_is_value_undefined (set_prop_value))
        {
          ret_value = ecma_raise_type_error (ECMA_ERR_MSG (""));
        }
        else
        {
          prop_desc.is_set_defined = true;

          if (ecma_is_value_undefined (set_prop_value))
          {
            prop_desc.set_p = NULL;
          }
          else
          {
            JERRY_ASSERT (ecma_is_value_object (set_prop_value));

            ecma_object_t *set_p = ecma_get_object_from_value (set_prop_value);
            ecma_ref_object (set_p);

            prop_desc.set_p = set_p;
          }
        }

        ECMA_FINALIZE (set_prop_value);
      }

      ecma_deref_ecma_string (set_magic_string_p);
    }

    if (!ecma_is_value_error (ret_value))
    {
      JERRY_ASSERT (ecma_is_value_empty (ret_value));

      // 9.
      if (prop_desc.is_get_defined
          || prop_desc.is_set_defined)
      {
        if (prop_desc.is_value_defined
            || prop_desc.is_writable_defined)
        {
          ret_value = ecma_raise_type_error (ECMA_ERR_MSG (""));
        }
      }
    }

    if (!ecma_is_value_error (ret_value))
    {
      JERRY_ASSERT (ecma_is_value_empty (ret_value));
    }
    else
    {
      ecma_free_property_descriptor (&prop_desc);
    }

    *out_prop_desc_p = prop_desc;
  }

  return ret_value;
} /* ecma_op_to_property_descriptor */
/**
 * Helper function for concatenating an ecma_value_t to an Array.
 *
 * See also:
 *          ECMA-262 v5, 15.4.4.4 steps 5.b - 5.c
 *
 * Used by:
 *         - The Array.prototype.concat routine.
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
 */
ecma_value_t
ecma_builtin_helper_array_concat_value (ecma_object_t *obj_p, /**< array */
                                        uint32_t *length_p, /**< [in,out] array's length */
                                        ecma_value_t value) /**< value to concat */
{
  ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  /* 5.b */
  if (ecma_is_value_object (value)
      && (ecma_object_get_class_name (ecma_get_object_from_value (value)) == LIT_MAGIC_STRING_ARRAY_UL))
  {
    ecma_string_t *magic_string_length_p = ecma_new_ecma_length_string ();
    /* 5.b.ii */
    ECMA_TRY_CATCH (arg_len_value,
                    ecma_op_object_get (ecma_get_object_from_value (value),
                                        magic_string_length_p),
                    ret_value);
    ECMA_OP_TO_NUMBER_TRY_CATCH (arg_len_number, arg_len_value, ret_value);

    uint32_t arg_len = ecma_number_to_uint32 (arg_len_number);

    /* 5.b.iii */
    for (uint32_t array_index = 0;
         array_index < arg_len && ecma_is_value_empty (ret_value);
         array_index++)
    {
      ecma_string_t *array_index_string_p = ecma_new_ecma_string_from_uint32 (array_index);

      /* 5.b.iii.2 */
      if (ecma_op_object_get_property (ecma_get_object_from_value (value),
                                       array_index_string_p) != NULL)
      {
        ecma_string_t *new_array_index_string_p = ecma_new_ecma_string_from_uint32 (*length_p + array_index);

        /* 5.b.iii.3.a */
        ECMA_TRY_CATCH (get_value,
                        ecma_op_object_get (ecma_get_object_from_value (value),
                                            array_index_string_p),
                        ret_value);

        /* 5.b.iii.3.b */
        /* This will always be a simple value since 'is_throw' is false, so no need to free. */
        ecma_value_t put_comp = ecma_builtin_helper_def_prop (obj_p,
                                                              new_array_index_string_p,
                                                              get_value,
                                                              true, /* Writable */
                                                              true, /* Enumerable */
                                                              true, /* Configurable */
                                                              false); /* Failure handling */

        JERRY_ASSERT (ecma_is_value_true (put_comp));

        ECMA_FINALIZE (get_value);
        ecma_deref_ecma_string (new_array_index_string_p);
      }

      ecma_deref_ecma_string (array_index_string_p);
    }

    *length_p += arg_len;

    ECMA_OP_TO_NUMBER_FINALIZE (arg_len_number);
    ECMA_FINALIZE (arg_len_value);
    ecma_deref_ecma_string (magic_string_length_p);
  }
  else
  {
    ecma_string_t *new_array_index_string_p = ecma_new_ecma_string_from_uint32 ((*length_p)++);

    /* 5.c.i */
    /* This will always be a simple value since 'is_throw' is false, so no need to free. */
    ecma_value_t put_comp = ecma_builtin_helper_def_prop (obj_p,
                                                          new_array_index_string_p,
                                                          value,
                                                          true, /* Writable */
                                                          true, /* Enumerable */
                                                          true, /* Configurable */
                                                          false); /* Failure handling */

    JERRY_ASSERT (ecma_is_value_true (put_comp));

    ecma_deref_ecma_string (new_array_index_string_p);
  }

  if (ecma_is_value_empty (ret_value))
  {
    ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
  }

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

  JERRY_ASSERT (!is_unresolvable_reference);
  JERRY_ASSERT (is_property_reference);

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

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

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

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

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

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


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

    if (prop_p == NULL)
    {
      // 3.
      ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
    }
    else if (prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDDATA)
    {
      // 4.
      ret_value = ecma_copy_value (ecma_get_named_data_property_value (prop_p), true);
    }
    else
    {
      // 5.
      JERRY_ASSERT (prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDACCESSOR);

      ecma_object_t *obj_p = ecma_get_named_accessor_property_getter (prop_p);

      // 6.
      if (obj_p == NULL)
      {
        ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
      }
      else
      {
        // 7.
        ret_value = ecma_op_function_call (obj_p, base, NULL, 0);
      }
    }

    ECMA_FINALIZE (obj_base);

    return ret_value;
  }
} /* ecma_op_get_value_object_base */
/**
 * The RegExp.prototype object's 'toString' routine
 *
 * See also:
 *          ECMA-262 v5, 15.10.6.4
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
 */
static ecma_value_t
ecma_builtin_regexp_prototype_to_string (ecma_value_t this_arg) /**< this argument */
{
  ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  if (!ecma_is_value_object (this_arg)
      || ecma_object_get_class_name (ecma_get_object_from_value (this_arg)) != LIT_MAGIC_STRING_REGEXP_UL)
  {
    ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Incomplete RegExp type"));
  }
  else
  {
    ECMA_TRY_CATCH (obj_this,
                    ecma_op_to_object (this_arg),
                    ret_value);

    ecma_object_t *obj_p = ecma_get_object_from_value (obj_this);

    /* Get RegExp source from the source property */
    ecma_string_t *magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE);
    ecma_property_t *source_prop_p = ecma_op_object_get_property (obj_p, magic_string_p);
    ecma_deref_ecma_string (magic_string_p);

    ecma_string_t *src_sep_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_SLASH_CHAR);
    ecma_string_t *source_str_p = ecma_get_string_from_value (ecma_get_named_data_property_value (source_prop_p));
    ecma_string_t *output_str_p = ecma_concat_ecma_strings (src_sep_str_p, source_str_p);

    ecma_string_t *concat_p = ecma_concat_ecma_strings (output_str_p, src_sep_str_p);
    ecma_deref_ecma_string (src_sep_str_p);
    ecma_deref_ecma_string (output_str_p);
    output_str_p = concat_p;

    /* Check the global flag */
    magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL);
    ecma_property_t *global_prop_p = ecma_op_object_get_property (obj_p, magic_string_p);
    ecma_deref_ecma_string (magic_string_p);

    if (ecma_is_value_true (ecma_get_named_data_property_value (global_prop_p)))
    {
      ecma_string_t *g_flag_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_G_CHAR);
      concat_p = ecma_concat_ecma_strings (output_str_p, g_flag_str_p);
      ecma_deref_ecma_string (output_str_p);
      ecma_deref_ecma_string (g_flag_str_p);
      output_str_p = concat_p;
    }

    /* Check the ignoreCase flag */
    magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL);
    ecma_property_t *ignorecase_prop_p = ecma_op_object_get_property (obj_p, magic_string_p);
    ecma_deref_ecma_string (magic_string_p);

    if (ecma_is_value_true (ecma_get_named_data_property_value (ignorecase_prop_p)))
    {
      ecma_string_t *ic_flag_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_I_CHAR);
      concat_p = ecma_concat_ecma_strings (output_str_p, ic_flag_str_p);
      ecma_deref_ecma_string (output_str_p);
      ecma_deref_ecma_string (ic_flag_str_p);
      output_str_p = concat_p;
    }

    /* Check the global flag */
    magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE);
    ecma_property_t *multiline_prop_p = ecma_op_object_get_property (obj_p, magic_string_p);
    ecma_deref_ecma_string (magic_string_p);

    if (ecma_is_value_true (ecma_get_named_data_property_value (multiline_prop_p)))
    {
      ecma_string_t *m_flag_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_M_CHAR);
      concat_p = ecma_concat_ecma_strings (output_str_p, m_flag_str_p);
      ecma_deref_ecma_string (output_str_p);
      ecma_deref_ecma_string (m_flag_str_p);
      output_str_p = concat_p;
    }

    ret_value = ecma_make_string_value (output_str_p);

    ECMA_FINALIZE (obj_this);
  }

  return ret_value;
} /* ecma_builtin_regexp_prototype_to_string */
/**
 * The RegExp.prototype object's 'compile' routine
 *
 * See also:
 *          ECMA-262 v5, B.2.5.1
 *
 * @return undefined        - if compiled successfully
 *         error ecma value - otherwise
 *
 *         Returned value must be freed with ecma_free_value.
 */
static ecma_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_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

  if (!ecma_is_value_object (this_arg)
      || ecma_object_get_class_name (ecma_get_object_from_value (this_arg)) != LIT_MAGIC_STRING_REGEXP_UL)
  {
    ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Incomplete RegExp 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 (ECMA_ERR_MSG ("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_op_object_get_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_op_object_get_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_op_object_get_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_op_object_get_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);

        ECMA_TRY_CATCH (obj_this, ecma_op_to_object (this_arg), ret_value);
        ecma_object_t *this_obj_p = ecma_get_object_from_value (obj_this);

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

        /* TODO: We currently have to re-compile the bytecode, because
         * we can't copy it without knowing its length. */
        const re_compiled_code_t *new_bc_p = NULL;
        ecma_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_value_empty (bc_comp));

        re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t,
                                                                        ecma_get_internal_property_value (bc_prop_p));
        if (old_bc_p != NULL)
        {
          /* Free the old bytecode */
          ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p);
        }

        ECMA_SET_INTERNAL_VALUE_POINTER (ECMA_PROPERTY_VALUE_PTR (bc_prop_p)->value, new_bc_p);

        re_initialize_props (this_obj_p, pattern_string_p, flags);

        ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);

        ECMA_FINALIZE (obj_this);
      }
    }
    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_is_empty (ecma_get_string_from_value (regexp_str_value)))
        {
          pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
        }
        else
        {
          pattern_string_p = ecma_get_string_from_value (regexp_str_value);
          ecma_ref_ecma_string (pattern_string_p);
        }

        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_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_value_empty (ret_value))
      {
        ECMA_TRY_CATCH (obj_this, ecma_op_to_object (this_arg), ret_value);
        ecma_object_t *this_obj_p = ecma_get_object_from_value (obj_this);

        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. */
        const 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_INTERNAL_VALUE_POINTER (re_compiled_code_t,
                                                                        ecma_get_internal_property_value (bc_prop_p));

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

        ECMA_SET_INTERNAL_VALUE_POINTER (ECMA_PROPERTY_VALUE_PTR (bc_prop_p)->value, new_bc_p);
        re_initialize_props (this_obj_p, pattern_string_p, flags);
        ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);

        ECMA_FINALIZE (bc_dummy);

        ECMA_FINALIZE (obj_this);
      }

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

  return ret_value;
} /* ecma_builtin_regexp_prototype_compile */
/**
 * Helper function for concatenating an ecma_value_t to an Array.
 *
 * See also:
 *          ECMA-262 v5, 15.4.4.4 steps 5.b - 5.c
 *
 * Used by:
 *         - The Array.prototype.concat routine.
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
ecma_completion_value_t
ecma_builtin_helper_array_concat_value (ecma_object_t *obj_p, /**< array */
                                        uint32_t *length_p, /**< in-out: array's length */
                                        ecma_value_t value) /**< value to concat */
{
  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

  /* 5.b */
  if (ecma_is_value_object (value)
      && (ecma_object_get_class_name (ecma_get_object_from_value (value)) == LIT_MAGIC_STRING_ARRAY_UL))
  {
    ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);
    /* 5.b.ii */
    ECMA_TRY_CATCH (arg_len_value,
                    ecma_op_object_get (ecma_get_object_from_value (value),
                                        magic_string_length_p),
                    ret_value);
    ECMA_OP_TO_NUMBER_TRY_CATCH (arg_len_number, arg_len_value, ret_value);

    uint32_t arg_len = ecma_number_to_uint32 (arg_len_number);

    /* 5.b.iii */
    for (uint32_t array_index = 0;
         array_index < arg_len && ecma_is_completion_value_empty (ret_value);
         array_index++)
    {
      ecma_string_t *array_index_string_p = ecma_new_ecma_string_from_uint32 (array_index);

      /* 5.b.iii.2 */
      if (ecma_op_object_get_property (ecma_get_object_from_value (value),
                                       array_index_string_p) != NULL)
      {
        ecma_string_t *new_array_index_string_p = ecma_new_ecma_string_from_uint32 (*length_p + array_index);

        /* 5.b.iii.3.a */
        ECMA_TRY_CATCH (get_value,
                        ecma_op_object_get (ecma_get_object_from_value (value),
                                            array_index_string_p),
                        ret_value);

        ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
        {
          prop_desc.is_value_defined = true;
          prop_desc.value = get_value;

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

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

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

        /* 5.b.iii.3.b */
        /* This will always be a simple value since 'is_throw' is false, so no need to free. */
        ecma_completion_value_t put_comp = ecma_op_object_define_own_property (obj_p,
                                                                               new_array_index_string_p,
                                                                               &prop_desc,
                                                                               false);
        JERRY_ASSERT (ecma_is_completion_value_normal_true (put_comp));

        ECMA_FINALIZE (get_value);
        ecma_deref_ecma_string (new_array_index_string_p);
      }

      ecma_deref_ecma_string (array_index_string_p);
    }

    *length_p += arg_len;

    ECMA_OP_TO_NUMBER_FINALIZE (arg_len_number);
    ECMA_FINALIZE (arg_len_value);
    ecma_deref_ecma_string (magic_string_length_p);
  }
  else
  {
    ecma_string_t *new_array_index_string_p = ecma_new_ecma_string_from_uint32 ((*length_p)++);

    ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
    {
      prop_desc.is_value_defined = true;
      prop_desc.value = value;

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

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

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

    /* 5.c.i */
    /* This will always be a simple value since 'is_throw' is false, so no need to free. */
    ecma_completion_value_t put_comp = ecma_op_object_define_own_property (obj_p,
                                                                           new_array_index_string_p,
                                                                           &prop_desc,
                                                                           false);
    JERRY_ASSERT (ecma_is_completion_value_normal_true (put_comp));

    ecma_deref_ecma_string (new_array_index_string_p);
  }

  if (ecma_is_completion_value_empty (ret_value))
  {
    ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE);
  }

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

  ecma_object_t *setter_p = NULL;

  ecma_property_t *prop_p = ecma_op_object_get_own_property (obj_p, property_name_p);

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

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

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

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

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

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

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

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

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

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

      uint32_t index;

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

        JERRY_ASSERT (!ecma_op_general_object_property_name_is_length (property_name_p));

        ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);
        ecma_property_t *len_prop_p = ecma_op_object_get_own_property (obj_p, magic_string_length_p);
        ecma_deref_ecma_string (magic_string_length_p);

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

        uint32_t old_len = ecma_get_uint32_from_value (ecma_get_named_data_property_value (len_prop_p));

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

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

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

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

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

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

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

  return ret_value;
} /* ecma_op_general_object_put */