diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index bfb78287e..35f52ab0c 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -31,6 +31,7 @@ #include "ecma-helpers.h" #include "ecma-init-finalize.h" #include "ecma-lex-env.h" +#include "lit-char-helpers.h" #include "ecma-literal-storage.h" #include "ecma-objects.h" #include "ecma-objects-general.h" @@ -1773,11 +1774,20 @@ jerry_create_regexp_sz (const jerry_char_t *pattern_p, /**< zero-terminated UTF- return jerry_throw (ecma_raise_common_error (ECMA_ERR_MSG ("Input must be a valid utf8 string"))); } + ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL); + + if (JERRY_UNLIKELY (regexp_obj_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + ecma_string_t *ecma_pattern = ecma_new_ecma_string_from_utf8 (pattern_p, pattern_size); - jerry_value_t ret_val = ecma_op_create_regexp_object (ecma_pattern, flags); - + jerry_value_t ret_val = ecma_op_create_regexp_with_flags (regexp_obj_p, + ecma_make_string_value (ecma_pattern), + flags); ecma_deref_ecma_string (ecma_pattern); + return ret_val; #else /* !ENABLED (JERRY_BUILTIN_REGEXP) */ diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 354424fbd..435669303 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -1106,17 +1106,24 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ ecma_dealloc_number (num_p); break; } - +#if ENABLED (JERRY_ES2015) + case LIT_INTERNAL_MAGIC_STRING_REGEXP_PROTO: + { + jmem_heap_free_block (ECMA_GET_INTERNAL_VALUE_POINTER (void, ext_object_p->u.class_prop.u.value), + ECMA_REGEXP_PROTO_COMPILED_CODE_SIZE); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ case LIT_MAGIC_STRING_REGEXP_UL: { - ecma_compiled_code_t *bytecode_p; - bytecode_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_compiled_code_t, - ext_object_p->u.class_prop.u.value); + ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_compiled_code_t, + ext_object_p->u.class_prop.u.value); if (bytecode_p != NULL) { ecma_bytecode_deref (bytecode_p); } + break; } #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index cabb67672..dd85aa5ff 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -940,6 +940,13 @@ typedef struct * If regexp, the other flags must be RE_FLAG... */ } ecma_compiled_code_t; +/** + * The proper memory size for the RegExp.prototype. We have to align the header's size manually, because + * in the struct, it is aligned to 8 bytes during the compilation. + */ +#define ECMA_REGEXP_PROTO_COMPILED_CODE_SIZE \ + (JERRY_ALIGNUP (sizeof (ecma_compiled_code_t), JMEM_ALIGNMENT) + sizeof (ecma_value_t)) + #if ENABLED (JERRY_SNAPSHOT_EXEC) /** diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index 5ea26922b..15049cb0b 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -1494,6 +1494,28 @@ ecma_compiled_code_get_tagged_template_collection (const ecma_compiled_code_t *b } /* ecma_compiled_code_get_tagged_template_collection */ #endif /* ENABLED (JERRY_ES2015) */ +/** + * Helper function to check if the given value is a class + * + * @return pointer to the extended object - if 'this' is a class + * NULL- otherwise + */ +ecma_extended_object_t * +ecma_op_check_object_type_is_class (ecma_value_t this) /**< this value */ +{ + if (ecma_is_value_object (this)) + { + ecma_object_t *obj_p = ecma_get_object_from_value (this); + + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_CLASS) + { + return (ecma_extended_object_t *) obj_p; + } + } + + return NULL; +} /* ecma_op_check_object_type_is_class */ + #if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) || ENABLED (JERRY_ES2015) /** * Get the number of formal parameters of the compiled code diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 46b7b3f29..1c05d5c6b 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -430,6 +430,7 @@ uint8_t ecma_get_object_builtin_id (ecma_object_t *object_p); ecma_lexical_environment_type_t JERRY_ATTR_PURE ecma_get_lex_env_type (const ecma_object_t *object_p); ecma_object_t JERRY_ATTR_PURE *ecma_get_lex_env_binding_object (const ecma_object_t *object_p); ecma_object_t *ecma_clone_decl_lexical_environment (ecma_object_t *lex_env_p, bool copy_values); +ecma_extended_object_t *ecma_op_check_object_type_is_class (ecma_value_t this); ecma_property_value_t * ecma_create_named_data_property (ecma_object_t *object_p, ecma_string_t *name_p, uint8_t prop_attributes, diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c index fabad3040..3901a2ddb 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c @@ -814,7 +814,7 @@ ecma_builtin_helper_def_prop_by_index (ecma_object_t *obj_p, /**< object */ */ ecma_value_t ecma_builtin_helper_def_prop (ecma_object_t *obj_p, /**< object */ - ecma_string_t *index_p, /**< index string */ + ecma_string_t *name_p, /**< name string */ ecma_value_t value, /**< value */ uint32_t opts) /**< any combination of ecma_property_flag_t bits * with the optional ECMA_IS_THROW flag */ @@ -826,7 +826,7 @@ ecma_builtin_helper_def_prop (ecma_object_t *obj_p, /**< object */ prop_desc.value = value; return ecma_op_object_define_own_property (obj_p, - index_p, + name_p, &prop_desc); } /* ecma_builtin_helper_def_prop */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h index cf6df4ace..96d457751 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h @@ -60,7 +60,7 @@ bool ecma_builtin_helper_string_find_index (ecma_string_t *original_str_p, ecma_string_t *search_str_p, bool first_index, ecma_length_t start_pos, ecma_length_t *ret_index_p); ecma_value_t -ecma_builtin_helper_def_prop (ecma_object_t *obj_p, ecma_string_t *index_p, ecma_value_t value, uint32_t opts); +ecma_builtin_helper_def_prop (ecma_object_t *obj_p, ecma_string_t *name_p, ecma_value_t value, uint32_t opts); ecma_value_t ecma_builtin_helper_def_prop_by_index (ecma_object_t *obj_p, uint32_t index, ecma_value_t value, uint32_t opts); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c index 6acf34b46..3f93bdadb 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c @@ -60,21 +60,23 @@ static ecma_value_t ecma_builtin_regexp_prototype_flags_helper (ecma_value_t this, /**< this value */ uint16_t *flags_p) /**< [out] flags */ { - if (!ecma_object_is_regexp_object (this)) + ecma_extended_object_t *ext_obj_p = ecma_op_check_object_type_is_class (this); + + if (ext_obj_p != NULL) { - return ecma_raise_type_error (ECMA_ERR_MSG ("Incompatible type")); + if (ext_obj_p->u.class_prop.class_id == LIT_MAGIC_STRING_REGEXP_UL + || ext_obj_p->u.class_prop.class_id == LIT_INTERNAL_MAGIC_STRING_REGEXP_PROTO) + { + re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + ext_obj_p->u.class_prop.u.value); + + *flags_p = bc_p->header.status_flags; + + return ECMA_VALUE_EMPTY; + } } - ecma_extended_object_t *re_obj_p = (ecma_extended_object_t *) ecma_get_object_from_value (this); - re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, - re_obj_p->u.class_prop.u.value); - - if (bc_p != NULL) - { - *flags_p = bc_p->header.status_flags; - } - - return ECMA_VALUE_EMPTY; + return ecma_raise_type_error (ECMA_ERR_MSG ("Incompatible type")); } /* ecma_builtin_regexp_prototype_flags_helper */ /** @@ -220,21 +222,21 @@ ecma_op_escape_regexp_pattern (ecma_string_t *pattern_str_p) /**< RegExp pattern static ecma_value_t ecma_builtin_regexp_prototype_get_source (ecma_value_t this_arg) /**< this argument */ { - if (!ecma_object_is_regexp_object (this_arg)) + ecma_extended_object_t *ext_obj_p = ecma_op_check_object_type_is_class (this_arg); + + if (ext_obj_p != NULL) { - return ecma_raise_type_error (ECMA_ERR_MSG ("Incompatible type")); + if (ext_obj_p->u.class_prop.class_id == LIT_MAGIC_STRING_REGEXP_UL + || ext_obj_p->u.class_prop.class_id == LIT_INTERNAL_MAGIC_STRING_REGEXP_PROTO) + { + re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + ext_obj_p->u.class_prop.u.value); + + return ecma_op_escape_regexp_pattern (ecma_get_string_from_value (bc_p->source)); + } } - ecma_extended_object_t *re_obj_p = (ecma_extended_object_t *) ecma_get_object_from_value (this_arg); - re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, - re_obj_p->u.class_prop.u.value); - - if (bc_p != NULL) - { - return ecma_op_escape_regexp_pattern (ecma_get_string_from_value (bc_p->source)); - } - - return ecma_make_string_value (ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP)); + return ecma_raise_type_error (ECMA_ERR_MSG ("Incompatible type")); } /* ecma_builtin_regexp_prototype_get_source */ /** @@ -382,95 +384,47 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument ecma_value_t flags_arg) /**< flags */ { if (!ecma_object_is_regexp_object (this_arg) - /* The builtin RegExp.prototype object does not have [[RegExpMatcher]] internal slot */ - || ecma_get_object_from_value (this_arg) == ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE)) +#if !ENABLED (JERRY_ES2015) + || ecma_get_object_from_value (this_arg) == ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE) +#endif /* !ENABLED (JERRY_ES2015) */ + ) { return ecma_raise_type_error (ECMA_ERR_MSG ("Incompatible type")); } - uint16_t flags = 0; + ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg); + ecma_ref_object (this_obj_p); - if (ecma_object_is_regexp_object (pattern_arg) - && ecma_get_object_from_value (pattern_arg) != ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE)) + ecma_value_t status = ecma_builtin_helper_def_prop (this_obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_uint32_value (0), + ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROP_IS_THROW); + + JERRY_ASSERT (ecma_is_value_true (status)); + + if (ecma_object_is_regexp_object (pattern_arg)) { if (!ecma_is_value_undefined (flags_arg)) { + ecma_deref_object (this_obj_p); return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument")); } - /* Compile from existing RegExp object. */ - ecma_extended_object_t *target_p = (ecma_extended_object_t *) ecma_get_object_from_value (pattern_arg); - re_compiled_code_t *target_bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, - target_p->u.class_prop.u.value); + ecma_extended_object_t *pattern_obj_p = (ecma_extended_object_t *) ecma_get_object_from_value (pattern_arg); + re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + pattern_obj_p->u.class_prop.u.value); - ecma_object_t *this_object_p = ecma_get_object_from_value (this_arg); - ecma_extended_object_t *current_p = (ecma_extended_object_t *) this_object_p; - - re_compiled_code_t *current_bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, - current_p->u.class_prop.u.value); - - JERRY_ASSERT (current_bc_p != NULL); - ecma_bytecode_deref ((ecma_compiled_code_t *) current_bc_p); - - JERRY_ASSERT (target_bc_p != NULL); - ecma_bytecode_ref ((ecma_compiled_code_t *) target_bc_p); - ECMA_SET_INTERNAL_VALUE_POINTER (current_p->u.class_prop.u.value, target_bc_p); - ecma_regexp_initialize_props (this_object_p, - ecma_get_string_from_value (target_bc_p->source), - target_bc_p->header.status_flags); - return ecma_copy_value (this_arg); + return ecma_op_create_regexp_from_bytecode (this_obj_p, bc_p); } - ecma_string_t *pattern_string_p = ecma_regexp_read_pattern_str_helper (pattern_arg); + ecma_value_t ret_value = ecma_op_create_regexp_from_pattern (this_obj_p, pattern_arg, flags_arg); - /* Get source string. */ - if (pattern_string_p == NULL) + if (ECMA_IS_VALUE_ERROR (ret_value)) { - return ECMA_VALUE_ERROR; + ecma_deref_object (this_obj_p); } - /* Parse flags. */ - if (!ecma_is_value_undefined (flags_arg)) - { - ecma_string_t *flags_str_p = ecma_op_to_string (flags_arg); - if (JERRY_UNLIKELY (flags_str_p == NULL)) - { - ecma_deref_ecma_string (pattern_string_p); - return ECMA_VALUE_ERROR; - } - - ecma_value_t parsed_flags_val = ecma_regexp_parse_flags (flags_str_p, &flags); - ecma_deref_ecma_string (flags_str_p); - - if (ECMA_IS_VALUE_ERROR (parsed_flags_val)) - { - ecma_deref_ecma_string (pattern_string_p); - return parsed_flags_val; - } - } - - /* Try to compile bytecode from new source. */ - const re_compiled_code_t *new_bc_p = NULL; - ecma_value_t bc_val = re_compile_bytecode (&new_bc_p, pattern_string_p, flags); - if (ECMA_IS_VALUE_ERROR (bc_val)) - { - ecma_deref_ecma_string (pattern_string_p); - return bc_val; - } - - ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg); - ecma_value_t *bc_prop_p = &(((ecma_extended_object_t *) this_obj_p)->u.class_prop.u.value); - - re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, *bc_prop_p); - - JERRY_ASSERT (old_bc_p != NULL); - ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p); - - ECMA_SET_INTERNAL_VALUE_POINTER (*bc_prop_p, new_bc_p); - ecma_regexp_initialize_props (this_obj_p, pattern_string_p, flags); - ecma_deref_ecma_string (pattern_string_p); - - return ecma_copy_value (this_arg); + return ret_value; } /* ecma_builtin_regexp_prototype_compile */ #endif /* ENABLED (JERRY_BUILTIN_ANNEXB) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c index 1de7784c3..48e814871 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c @@ -17,7 +17,9 @@ #include "ecma-builtins.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" +#include "ecma-gc.h" #include "ecma-helpers.h" +#include "jcontext.h" #include "ecma-objects.h" #include "ecma-regexp-object.h" #include "ecma-try-catch-macro.h" @@ -41,34 +43,15 @@ * @{ */ -/** - * Handle calling [[Call]] of built-in RegExp object - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -ecma_value_t -ecma_builtin_regexp_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ - ecma_length_t arguments_list_len) /**< number of arguments */ -{ - return ecma_builtin_regexp_dispatch_construct (arguments_list_p, arguments_list_len); -} /* ecma_builtin_regexp_dispatch_call */ - -/** - * Handle calling [[Construct]] of built-in RegExp object - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -ecma_value_t -ecma_builtin_regexp_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ - ecma_length_t arguments_list_len) /**< number of arguments */ +static ecma_value_t +ecma_builtin_regexp_dispatch_helper (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len, /**< number of arguments */ + ecma_object_t *new_target_p) /**< pointer to the new target object */ { ecma_value_t pattern_value = ECMA_VALUE_UNDEFINED; ecma_value_t flags_value = ECMA_VALUE_UNDEFINED; #if ENABLED (JERRY_ES2015) - ecma_value_t new_pattern = ECMA_VALUE_EMPTY; - ecma_value_t new_flags = ECMA_VALUE_EMPTY; + bool create_regexp_from_bc = false; #endif /* ENABLED (JERRY_ES2015) */ if (arguments_list_len > 0) @@ -90,88 +73,140 @@ ecma_builtin_regexp_dispatch_construct (const ecma_value_t *arguments_list_p, /* return regexp_value; } - bool is_regexp = regexp_value == ECMA_VALUE_TRUE; -#else /* !ENABLED (JERRY_ES2015) */ - bool is_regexp = ecma_object_is_regexp_object (pattern_value); -#endif /* ENABLED (JERRY_ES2015) */ + bool pattern_is_regexp = regexp_value == ECMA_VALUE_TRUE; + re_compiled_code_t *bc_p = NULL; - if (is_regexp) + if (new_target_p == NULL) + { + new_target_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP); + + if (pattern_is_regexp && ecma_is_value_undefined (flags_value)) + { + ecma_object_t *pattern_obj_p = ecma_get_object_from_value (pattern_value); + + ecma_value_t pattern_constructor = ecma_op_object_get_by_magic_id (pattern_obj_p, LIT_MAGIC_STRING_CONSTRUCTOR); + + if (ECMA_IS_VALUE_ERROR (pattern_constructor)) + { + return pattern_constructor; + } + + bool is_same = ecma_op_same_value (ecma_make_object_value (new_target_p), pattern_constructor); + ecma_free_value (pattern_constructor); + + if (is_same) + { + return ecma_copy_value (pattern_value); + } + } + } + + if (ecma_object_is_regexp_object (pattern_value)) + { + ecma_extended_object_t *pattern_obj_p = (ecma_extended_object_t *) ecma_get_object_from_value (pattern_value); + bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + pattern_obj_p->u.class_prop.u.value); + + create_regexp_from_bc = ecma_is_value_undefined (flags_value); + + if (!create_regexp_from_bc) + { + pattern_value = bc_p->source; + } + } + else if (pattern_is_regexp) { -#if ENABLED (JERRY_ES2015) ecma_object_t *pattern_obj_p = ecma_get_object_from_value (pattern_value); - new_pattern = ecma_op_object_get_by_magic_id (pattern_obj_p, LIT_MAGIC_STRING_SOURCE); + pattern_value = ecma_op_object_get_by_magic_id (pattern_obj_p, LIT_MAGIC_STRING_SOURCE); - if (ECMA_IS_VALUE_ERROR (new_pattern)) + if (ECMA_IS_VALUE_ERROR (pattern_value)) { - return new_pattern; + return pattern_value; } - pattern_value = new_pattern; - if (ecma_is_value_undefined (flags_value)) { - new_flags = ecma_op_object_get_by_magic_id (pattern_obj_p, LIT_MAGIC_STRING_FLAGS); + flags_value = ecma_op_object_get_by_magic_id (pattern_obj_p, LIT_MAGIC_STRING_FLAGS); - if (ECMA_IS_VALUE_ERROR (new_flags)) + if (ECMA_IS_VALUE_ERROR (flags_value)) { - ecma_free_value (new_pattern); - return new_flags; + return flags_value; } - - flags_value = new_flags; } + } #else /* !ENABLED (JERRY_ES2015) */ + if (ecma_object_is_regexp_object (pattern_value)) + { if (ecma_is_value_undefined (flags_value)) { return ecma_copy_value (pattern_value); } return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument of RegExp call.")); + } #endif /* ENABLED (JERRY_ES2015) */ - } - ecma_string_t *pattern_string_p = ecma_regexp_read_pattern_str_helper (pattern_value); - ecma_value_t ret_value = ECMA_VALUE_ERROR; + ecma_object_t *new_target_obj_p = ecma_op_regexp_alloc (new_target_p); - if (pattern_string_p == NULL) + if (JERRY_UNLIKELY (new_target_obj_p == NULL)) { - goto cleanup; + return ECMA_VALUE_ERROR; } - uint16_t flags = 0; + ecma_value_t ret_value; - if (!ecma_is_value_undefined (flags_value)) - { - ecma_string_t *flags_string_p = ecma_op_to_string (flags_value); - - if (JERRY_UNLIKELY (flags_string_p == NULL)) - { - ecma_deref_ecma_string (pattern_string_p); - goto cleanup; - } - - ret_value = ecma_regexp_parse_flags (flags_string_p, &flags); - ecma_deref_ecma_string (flags_string_p); - - if (ECMA_IS_VALUE_ERROR (ret_value)) - { - ecma_deref_ecma_string (pattern_string_p); - goto cleanup; - } - JERRY_ASSERT (ecma_is_value_empty (ret_value)); - } - - ret_value = ecma_op_create_regexp_object (pattern_string_p, flags); - ecma_deref_ecma_string (pattern_string_p); - -cleanup: #if ENABLED (JERRY_ES2015) - ecma_free_value (new_pattern); - ecma_free_value (new_flags); + if (create_regexp_from_bc) + { + ret_value = ecma_op_create_regexp_from_bytecode (new_target_obj_p, bc_p); + } + else + { #endif /* ENABLED (JERRY_ES2015) */ + ret_value = ecma_op_create_regexp_from_pattern (new_target_obj_p, pattern_value, flags_value); + +#if ENABLED (JERRY_ES2015) + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + ecma_deref_object (new_target_obj_p); + } + return ret_value; +} /* ecma_builtin_regexp_dispatch_helper */ + +/** + * Handle calling [[Call]] of built-in RegExp object + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_builtin_regexp_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_builtin_regexp_dispatch_helper (arguments_list_p, + arguments_list_len, + NULL); +} /* ecma_builtin_regexp_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in RegExp object + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_builtin_regexp_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_builtin_regexp_dispatch_helper (arguments_list_p, + arguments_list_len, + ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP)); } /* ecma_builtin_regexp_dispatch_construct */ #if ENABLED (JERRY_ES2015) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c index abb186d4d..815fd8255 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c @@ -283,93 +283,98 @@ ecma_builtin_string_prototype_object_locale_compare (ecma_string_t *this_string_ * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_string_prototype_object_match (ecma_value_t this_to_string_value, /**< this argument */ +ecma_builtin_string_prototype_object_match (ecma_value_t this_argument, /**< this argument */ ecma_value_t regexp_arg) /**< routine's argument */ { #if ENABLED (JERRY_ES2015) + /* 3. */ if (!(ecma_is_value_undefined (regexp_arg) || ecma_is_value_null (regexp_arg))) { + /* 3.a */ ecma_value_t matcher = ecma_op_get_method_by_symbol_id (regexp_arg, LIT_GLOBAL_SYMBOL_MATCH); + /* 3.b */ if (ECMA_IS_VALUE_ERROR (matcher)) { return matcher; } + /* 3.c */ if (!ecma_is_value_undefined (matcher)) { + /* 3.c.i */ ecma_object_t *matcher_method = ecma_get_object_from_value (matcher); - ecma_value_t result = ecma_op_function_call (matcher_method, regexp_arg, &this_to_string_value, 1); + ecma_value_t result = ecma_op_function_call (matcher_method, regexp_arg, &this_argument, 1); ecma_deref_object (matcher_method); return result; } } + + /* 4. */ + ecma_string_t *this_str_p = ecma_op_to_string (this_argument); + + /* 5. */ + if (JERRY_UNLIKELY (this_str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + /* 6. */ + ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL); + + if (JERRY_UNLIKELY (regexp_obj_p == NULL)) + { + ecma_deref_ecma_string (this_str_p); + return ECMA_VALUE_ERROR; + } + + ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (regexp_obj_p, regexp_arg, ECMA_VALUE_UNDEFINED); + + /* 7. */ + if (ECMA_IS_VALUE_ERROR (new_regexp)) + { + + ecma_deref_object (regexp_obj_p); + ecma_deref_ecma_string (this_str_p); + return new_regexp; + } + ecma_value_t this_str_value = ecma_make_string_value (this_str_p); + + /* 8. */ + ecma_value_t ret_value = ecma_op_invoke_by_symbol_id (new_regexp, LIT_GLOBAL_SYMBOL_MATCH, &this_str_value, 1); + + ecma_deref_ecma_string (this_str_p); + ecma_free_value (new_regexp); + + return ret_value; + #else /* !ENABLED (JERRY_ES2015) */ if (ecma_object_is_regexp_object (regexp_arg)) { - return ecma_regexp_match_helper (regexp_arg, this_to_string_value); + return ecma_regexp_match_helper (regexp_arg, this_argument); } -#endif /* ENABLED (JERRY_ES2015) */ - ecma_string_t *pattern_p = ecma_regexp_read_pattern_str_helper (regexp_arg); + ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL); - if (JERRY_UNLIKELY (pattern_p == NULL)) + if (JERRY_UNLIKELY (regexp_obj_p == NULL)) { return ECMA_VALUE_ERROR; } - ecma_value_t new_regexp = ecma_op_create_regexp_object (pattern_p, 0); - - ecma_deref_ecma_string (pattern_p); + ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (regexp_obj_p, regexp_arg, ECMA_VALUE_UNDEFINED); if (ECMA_IS_VALUE_ERROR (new_regexp)) { + ecma_deref_object (regexp_obj_p); return new_regexp; } -#if ENABLED (JERRY_ES2015) - ecma_object_t *new_regexp_obj = ecma_get_object_from_value (new_regexp); - - ecma_value_t func_value = ecma_op_object_get_by_symbol_id (new_regexp_obj, LIT_GLOBAL_SYMBOL_MATCH); - - if (ECMA_IS_VALUE_ERROR (func_value) || !ecma_op_is_callable (func_value)) - { - ecma_deref_object (new_regexp_obj); - - if (!ECMA_IS_VALUE_ERROR (func_value)) - { - ecma_free_value (func_value); - ecma_raise_type_error (ECMA_ERR_MSG ("@@match is not callable.")); - } - - return ECMA_VALUE_ERROR; - } - - ecma_object_t *func_obj = ecma_get_object_from_value (func_value); - - ecma_string_t *str_p = ecma_op_to_string (this_to_string_value); - - if (JERRY_UNLIKELY (str_p == NULL)) - { - ecma_deref_object (new_regexp_obj); - ecma_deref_object (func_obj); - return ECMA_VALUE_ERROR; - } - - ecma_value_t str_value = ecma_make_string_value (str_p); - - ecma_value_t result = ecma_op_function_call (func_obj, new_regexp, &str_value, 1); - - ecma_deref_ecma_string (str_p); - ecma_deref_object (new_regexp_obj); - ecma_deref_object (func_obj); -#else /* !ENABLED (JERRY_ES2015) */ - ecma_value_t result = ecma_regexp_match_helper (new_regexp, this_to_string_value); + ecma_value_t result = ecma_regexp_match_helper (new_regexp, this_argument); ecma_free_value (new_regexp); -#endif /* ENABLED (JERRY_ES2015) */ return result; +#endif /* ENABLED (JERRY_ES2015) */ } /* ecma_builtin_string_prototype_object_match */ /** @@ -624,10 +629,24 @@ ecma_builtin_string_prototype_object_search (ecma_value_t this_value, /**< this goto cleanup_string; } - ecma_value_t new_regexp = ecma_op_create_regexp_object (pattern_p, 0); + ecma_object_t *new_regexp_obj_p = ecma_op_regexp_alloc (NULL); + + if (JERRY_UNLIKELY (new_regexp_obj_p == NULL)) + { + ecma_deref_ecma_string (string_p); + ecma_deref_ecma_string (pattern_p); + return ECMA_VALUE_ERROR; + } + + ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (new_regexp_obj_p, + ecma_make_string_value (pattern_p), + ECMA_VALUE_UNDEFINED); + ecma_deref_ecma_string (pattern_p); + if (ECMA_IS_VALUE_ERROR (new_regexp)) { + ecma_deref_object (new_regexp_obj_p); goto cleanup_string; } @@ -1323,6 +1342,13 @@ ecma_builtin_string_prototype_dispatch_routine (uint16_t builtin_routine_id, /** ecma_value_t arg1 = arguments_list_p[0]; ecma_value_t arg2 = arguments_list_p[1]; +#if ENABLED (JERRY_BUILTIN_REGEXP) + if (builtin_routine_id == ECMA_STRING_PROTOTYPE_MATCH) + { + return ecma_builtin_string_prototype_object_match (this_arg, arg1); + } +#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ + if (builtin_routine_id <= ECMA_STRING_PROTOTYPE_CHAR_CODE_AT) { return ecma_builtin_string_prototype_char_at_helper (this_arg, @@ -1371,11 +1397,6 @@ ecma_builtin_string_prototype_dispatch_routine (uint16_t builtin_routine_id, /** break; } #if ENABLED (JERRY_BUILTIN_REGEXP) - case ECMA_STRING_PROTOTYPE_MATCH: - { - ret_value = ecma_builtin_string_prototype_object_match (to_string_val, arg1); - break; - } case ECMA_STRING_PROTOTYPE_REPLACE: { ret_value = ecma_builtin_string_prototype_object_replace (to_string_val, arg1, arg2); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.c b/jerry-core/ecma/builtin-objects/ecma-builtins.c index 5c239362a..5db3e96d4 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.c @@ -501,8 +501,32 @@ ecma_instantiate_builtin (ecma_builtin_id_t obj_builtin_id) /**< built-in id */ JERRY_ASSERT (obj_type == ECMA_OBJECT_TYPE_CLASS); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; +#if ENABLED (JERRY_ES2015) + ext_object_p->u.class_prop.class_id = LIT_INTERNAL_MAGIC_STRING_REGEXP_PROTO; +#else /* !ENABLED (JERRY_ES2015) */ ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_REGEXP_UL; - ext_object_p->u.class_prop.u.value = ECMA_NULL_POINTER; +#endif /* ENABLED (JERRY_ES2015) */ + +/* In the ECMA v6 version, we create a dummy bytecode for the RegExp prototype object for backwards compatibility, + * so we can use the existing methods to get the source and flags from the [[OriginalSource]] and [[OriginalFlags]] + * internal properties. + */ +#if ENABLED (JERRY_ES2015) + re_compiled_code_t *bc_p = (re_compiled_code_t *) jmem_heap_alloc_block (ECMA_REGEXP_PROTO_COMPILED_CODE_SIZE); + + bc_p->header.status_flags = RE_FLAG_EMPTY; + bc_p->source = ecma_make_magic_string_value (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP); +#else /* !ENABLED (JERRY_ES2015) */ + const re_compiled_code_t *bc_p = NULL; + ecma_value_t ret_value = re_compile_bytecode (&bc_p, + ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP), + RE_FLAG_EMPTY); + + JERRY_ASSERT (ecma_is_value_empty (ret_value)); +#endif /* ENABLED (JERRY_ES2015) */ + + ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.class_prop.u.value, bc_p); + break; } #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 991a3f2a2..3042cfafd 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -2506,6 +2506,14 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ case ECMA_OBJECT_TYPE_CLASS: { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; + +#if ENABLED (JERRY_ES2015) + if (ext_object_p->u.class_prop.class_id == LIT_INTERNAL_MAGIC_STRING_REGEXP_PROTO) + { + return LIT_MAGIC_STRING_REGEXP_UL; + } +#endif /* ENABLED (JERRY_ES2015) */ + return (lit_magic_string_id_t) ext_object_p->u.class_prop.class_id; } case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: @@ -2790,6 +2798,24 @@ ecma_op_species_constructor (ecma_object_t *this_value, /**< This Value */ return species; } /* ecma_op_species_constructor */ +/** + * 7.3.18 Abstract operation Invoke when property name is a magic string + * + * @return ecma_value result of the invoked function or raised error + * note: returned value must be freed with ecma_free_value + */ +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE +ecma_op_invoke_by_symbol_id (ecma_value_t object, /**< Object value */ + lit_magic_string_id_t symbol_id, /**< Symbol ID */ + ecma_value_t *args_p, /**< Argument list */ + ecma_length_t args_len) /**< Argument list length */ +{ + ecma_string_t *symbol_p = ecma_op_get_global_symbol (symbol_id); + ecma_value_t ret_value = ecma_op_invoke (object, symbol_p, args_p, args_len); + ecma_deref_ecma_string (symbol_p); + + return ret_value; +} /* ecma_op_invoke_by_symbol_id */ #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/ecma/operations/ecma-objects.h b/jerry-core/ecma/operations/ecma-objects.h index 26a8df369..5f287bf09 100644 --- a/jerry-core/ecma/operations/ecma-objects.h +++ b/jerry-core/ecma/operations/ecma-objects.h @@ -77,6 +77,8 @@ bool ecma_object_is_regexp_object (ecma_value_t arg); ecma_value_t ecma_op_is_concat_spreadable (ecma_value_t arg); ecma_value_t ecma_op_is_regexp (ecma_value_t arg); ecma_value_t ecma_op_species_constructor (ecma_object_t *this_value, ecma_builtin_id_t default_constructor_id); +ecma_value_t ecma_op_invoke_by_symbol_id (ecma_value_t object, lit_magic_string_id_t magic_string_id, + ecma_value_t *args_p, ecma_length_t args_len); #endif /* ENABLED (JERRY_ES2015) */ ecma_value_t ecma_op_invoke (ecma_value_t object, ecma_string_t *property_name_p, ecma_value_t *args_p, ecma_length_t args_len); diff --git a/jerry-core/ecma/operations/ecma-regexp-object.c b/jerry-core/ecma/operations/ecma-regexp-object.c index 1bc6927d0..2a50f5277 100644 --- a/jerry-core/ecma/operations/ecma-regexp-object.c +++ b/jerry-core/ecma/operations/ecma-regexp-object.c @@ -125,88 +125,81 @@ ecma_regexp_parse_flags (ecma_string_t *flags_str_p, /**< Input string with flag return ret_value; } /* ecma_regexp_parse_flags */ +#if !ENABLED (JERRY_ES2015) /* * Create the properties of a RegExp instance. */ static void -ecma_regexp_create_props (ecma_object_t *re_object_p) /**< RegExp object */ +ecma_regexp_create_props (ecma_object_t *re_object_p, /**< RegExp object */ + ecma_string_t *source_p, /**< source string */ + uint16_t flags) /**< flags */ { -#if !ENABLED (JERRY_ES2015) - ecma_create_named_data_property (re_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE), - ECMA_PROPERTY_FIXED, - NULL); - ecma_create_named_data_property (re_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL), - ECMA_PROPERTY_FIXED, - NULL); - ecma_create_named_data_property (re_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL), - ECMA_PROPERTY_FIXED, - NULL); - ecma_create_named_data_property (re_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE), - ECMA_PROPERTY_FIXED, - NULL); -#endif /* !ENABLED (JERRY_ES2015) */ - ecma_create_named_data_property (re_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), - ECMA_PROPERTY_FLAG_WRITABLE, - NULL); + ecma_property_value_t *prop_value_p; + + prop_value_p = ecma_create_named_data_property (re_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE), + ECMA_PROPERTY_FIXED, + NULL); + + ecma_ref_ecma_string (source_p); + prop_value_p->value = ecma_make_string_value (source_p); + + prop_value_p = ecma_create_named_data_property (re_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL), + ECMA_PROPERTY_FIXED, + NULL); + + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_GLOBAL); + + prop_value_p = ecma_create_named_data_property (re_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL), + ECMA_PROPERTY_FIXED, + NULL); + + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_IGNORE_CASE); + + prop_value_p = ecma_create_named_data_property (re_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE), + ECMA_PROPERTY_FIXED, + NULL); + + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_MULTILINE); } /* ecma_regexp_create_props */ /* - * Helper function to assign a value to a property + * Update the properties of a RegExp instance. */ static void -ecma_regexp_helper_assign_prop (ecma_object_t *re_object_p, /**< RegExp object */ - lit_magic_string_id_t prop_id, /**< property name ide */ - ecma_value_t value) /**< value */ +ecma_regexp_update_props (ecma_object_t *re_object_p, /**< RegExp object */ + ecma_string_t *source_p, /**< source string */ + uint16_t flags) /**< flags */ { - ecma_property_ref_t property_ref; - ecma_op_object_get_own_property (re_object_p, - ecma_get_magic_string (prop_id), - &property_ref, - ECMA_PROPERTY_GET_VALUE); - ecma_named_data_property_assign_value (re_object_p, - property_ref.value_p, - value); -} /* ecma_regexp_helper_assign_prop */ + ecma_property_t *prop_p; -/** - * Initializes the properties of a RegExp instance. - */ -void -ecma_regexp_initialize_props (ecma_object_t *re_object_p, /**< RegExp object */ - ecma_string_t *source_p, /**< source string */ - uint16_t flags) /**< flags */ -{ -#if !ENABLED (JERRY_ES2015) - ecma_regexp_helper_assign_prop (re_object_p, - LIT_MAGIC_STRING_SOURCE, - ecma_make_string_value (source_p)); + prop_p = ecma_find_named_property (re_object_p, ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE)); + JERRY_ASSERT (prop_p != NULL); + ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p); + ecma_free_value (prop_value_p->value); + ecma_ref_ecma_string (source_p); + prop_value_p->value = ecma_make_string_value (source_p); - ecma_regexp_helper_assign_prop (re_object_p, - LIT_MAGIC_STRING_GLOBAL, - ecma_make_boolean_value (flags & RE_FLAG_GLOBAL)); + prop_p = ecma_find_named_property (re_object_p, ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL)); + JERRY_ASSERT (prop_p != NULL); + prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p); + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_GLOBAL); - ecma_regexp_helper_assign_prop (re_object_p, - LIT_MAGIC_STRING_IGNORECASE_UL, - ecma_make_boolean_value (flags & RE_FLAG_IGNORE_CASE)); + prop_p = ecma_find_named_property (re_object_p, ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL)); + JERRY_ASSERT (prop_p != NULL); + prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p); + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_IGNORE_CASE); - ecma_regexp_helper_assign_prop (re_object_p, - LIT_MAGIC_STRING_MULTILINE, - ecma_make_boolean_value (flags & RE_FLAG_MULTILINE)); -#else /* ENABLED (JERRY_ES2015) */ - JERRY_UNUSED (source_p); - JERRY_UNUSED (flags); + prop_p = ecma_find_named_property (re_object_p, ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE)); + JERRY_ASSERT (prop_p != NULL); + prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p); + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_MULTILINE); +} /* ecma_regexp_update_props */ #endif /* !ENABLED (JERRY_ES2015) */ - ecma_regexp_helper_assign_prop (re_object_p, - LIT_MAGIC_STRING_LASTINDEX_UL, - ecma_make_uint32_value (0)); -} /* ecma_regexp_initialize_props */ - #if ENABLED (JERRY_ES2015) /** * Helper function to get current code point and advance the string pointer. @@ -238,86 +231,232 @@ ecma_regexp_unicode_advance (const lit_utf8_byte_t **str_p, /**< reference to st #endif /* ENABLED (JERRY_ES2015) */ /** - * RegExp object creation operation. + * RegExpAlloc method * * See also: ECMA-262 v5, 15.10.4.1 + * ECMA-262 v6, 21.2.3.2.1 * - * @return constructed RegExp object - * Returned value must be freed with ecma_free_value + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return ecma_object_t */ -ecma_value_t -ecma_op_create_regexp_object_from_bytecode (re_compiled_code_t *bytecode_p) /**< RegExp bytecode */ +ecma_object_t * +ecma_op_regexp_alloc (ecma_object_t *ctr_obj_p) /**< constructor object pointer */ { - JERRY_ASSERT (bytecode_p != NULL); +#if ENABLED (JERRY_ES2015) + bool default_alloc = false; - ecma_object_t *re_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE); + if (ctr_obj_p == NULL) + { + ecma_object_t *re_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE); - ecma_object_t *object_p = ecma_create_object (re_prototype_obj_p, - sizeof (ecma_extended_object_t), - ECMA_OBJECT_TYPE_CLASS); + ecma_value_t ctr_value = ecma_op_object_get_by_magic_id (re_prototype_obj_p, LIT_MAGIC_STRING_CONSTRUCTOR); - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + if (ECMA_IS_VALUE_ERROR (ctr_value)) + { + return NULL; + } - /* Set the internal [[Class]] property */ - ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_REGEXP_UL; + ctr_obj_p = ecma_get_object_from_value (ctr_value); - /* Set bytecode internal property. */ - ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.class_prop.u.value, bytecode_p); - ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_p); + default_alloc = true; + } - /* Create and initialize RegExp object properties */ - ecma_regexp_create_props (object_p); - ecma_regexp_initialize_props (object_p, - ecma_get_string_from_value (bytecode_p->source), - bytecode_p->header.status_flags); + ecma_object_t *proto_obj_p = ecma_op_get_prototype_from_constructor (ctr_obj_p, + ECMA_BUILTIN_ID_REGEXP_PROTOTYPE); - return ecma_make_object_value (object_p); -} /* ecma_op_create_regexp_object_from_bytecode */ + if (default_alloc) + { + ecma_deref_object (ctr_obj_p); + } + + if (JERRY_UNLIKELY (proto_obj_p == NULL)) + { + return proto_obj_p; + } + +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_UNUSED (ctr_obj_p); + ecma_object_t *proto_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE); +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_object_t *new_object_p = ecma_create_object (proto_obj_p, + sizeof (ecma_extended_object_t), + ECMA_OBJECT_TYPE_CLASS); + +#if ENABLED (JERRY_ES2015) + ecma_deref_object (proto_obj_p); +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_extended_object_t *regexp_obj_p = (ecma_extended_object_t *) new_object_p; + regexp_obj_p->u.class_prop.u.value = JMEM_CP_NULL; + regexp_obj_p->u.class_prop.class_id = LIT_MAGIC_STRING_REGEXP_UL; + + ecma_value_t status = ecma_builtin_helper_def_prop (new_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_uint32_value (0), + ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROP_IS_THROW); + + JERRY_ASSERT (ecma_is_value_true (status)); + + return new_object_p; +} /* ecma_op_regexp_alloc */ /** - * RegExp object creation operation. + * Helper method for initializing an aready existing RegExp object. + */ +static void +ecma_op_regexp_initialize (ecma_object_t *regexp_obj_p, /**< RegExp object */ + const re_compiled_code_t *bc_p, /**< bytecode */ + ecma_string_t *pattern_str_p, /**< pattern */ + uint16_t flags) /**< flags */ +{ + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) regexp_obj_p; + + if (JERRY_UNLIKELY (ext_obj_p->u.class_prop.u.value != JMEM_CP_NULL)) + { + re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + ext_obj_p->u.class_prop.u.value); + + ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p); + +#if !ENABLED (JERRY_ES2015) + ecma_regexp_update_props (regexp_obj_p, pattern_str_p, flags); +#endif /* !ENABLED (JERRY_ES2015) */ + } +#if !ENABLED (JERRY_ES2015) + else + { + ecma_regexp_create_props (regexp_obj_p, pattern_str_p, flags); + } +#endif /* !ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_ES2015) + JERRY_UNUSED (pattern_str_p); + JERRY_UNUSED (flags); +#endif /* ENABLED (JERRY_ES2015) */ + + ECMA_SET_INTERNAL_VALUE_POINTER (ext_obj_p->u.class_prop.u.value, bc_p); +} /* ecma_op_regexp_initialize */ + +/** + * Method for creating a RegExp object from pattern. * - * See also: ECMA-262 v5, 15.10.4.1 + * Note: + * Allocation have to happen before invoking this function using ecma_op_regexp_alloc. * - * @return constructed RegExp object - if pattern and flags were parsed successfully - * error ecma value - otherwise - * - * Returned value must be freed with ecma_free_value + * @return ecma_value_t */ ecma_value_t -ecma_op_create_regexp_object (ecma_string_t *pattern_p, /**< input pattern */ - uint16_t flags) /**< flags */ +ecma_op_create_regexp_from_pattern (ecma_object_t *regexp_obj_p, /**< RegExp object */ + ecma_value_t pattern_value, /**< pattern */ + ecma_value_t flags_value) /**< flags */ { - JERRY_ASSERT (pattern_p != NULL); + ecma_string_t *pattern_str_p = ecma_regexp_read_pattern_str_helper (pattern_value); + uint16_t flags = 0; - ecma_object_t *re_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE); + if (JERRY_UNLIKELY (pattern_str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } - ecma_object_t *object_p = ecma_create_object (re_prototype_obj_p, - sizeof (ecma_extended_object_t), - ECMA_OBJECT_TYPE_CLASS); - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_UNDEFINED; + if (!ecma_is_value_undefined (flags_value)) + { + ecma_string_t *flags_str_p = ecma_op_to_string (flags_value); - ecma_regexp_create_props (object_p); - ecma_regexp_initialize_props (object_p, pattern_p, flags); + if (JERRY_UNLIKELY (flags_str_p == NULL)) + { + ecma_deref_ecma_string (pattern_str_p); + return ECMA_VALUE_ERROR; + } + + ecma_value_t parse_flags_value = ecma_regexp_parse_flags (flags_str_p, &flags); + ecma_deref_ecma_string (flags_str_p); + + if (ECMA_IS_VALUE_ERROR (parse_flags_value)) + { + ecma_deref_ecma_string (pattern_str_p); + return parse_flags_value; + } + + JERRY_ASSERT (ecma_is_value_empty (parse_flags_value)); + } - /* Compile bytecode. */ const re_compiled_code_t *bc_p = NULL; - ecma_value_t ret_value = re_compile_bytecode (&bc_p, pattern_p, flags); + ecma_value_t ret_value = re_compile_bytecode (&bc_p, pattern_str_p, flags); + ecma_deref_ecma_string (pattern_str_p); + if (ECMA_IS_VALUE_ERROR (ret_value)) { - ecma_deref_object (object_p); return ret_value; } JERRY_ASSERT (ecma_is_value_empty (ret_value)); - /* Set [[Class]] and bytecode internal properties. */ - ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_REGEXP_UL; - ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.class_prop.u.value, bc_p); + ecma_op_regexp_initialize (regexp_obj_p, bc_p, pattern_str_p, flags); - return ecma_make_object_value (object_p); -} /* ecma_op_create_regexp_object */ + return ecma_make_object_value (regexp_obj_p); +} /* ecma_op_create_regexp_from_pattern */ + +/** + * Method for creating a RegExp object from bytecode. + * + * Note: + * Allocation have to happen before invoking this function using ecma_op_regexp_alloc. + * + * @return ecma_value_t + */ +ecma_value_t +ecma_op_create_regexp_from_bytecode (ecma_object_t *regexp_obj_p, /**< RegExp object */ + re_compiled_code_t *bc_p) /**< bytecode */ +{ + ecma_bytecode_ref ((ecma_compiled_code_t *) bc_p); + ecma_string_t *pattern_str_p = ecma_get_string_from_value (bc_p->source); + uint16_t flags = bc_p->header.status_flags; + + ecma_op_regexp_initialize (regexp_obj_p, bc_p, pattern_str_p, flags); + + return ecma_make_object_value (regexp_obj_p); +} /* ecma_op_create_regexp_from_bytecode */ + +/** + * Method for creating a RegExp object from pattern with already parsed flags. + * + * Note: + * Allocation have to happen before invoking this function using ecma_op_regexp_alloc. + * + * @return ecma_value_t + */ +ecma_value_t +ecma_op_create_regexp_with_flags (ecma_object_t *regexp_obj_p, /**< RegExp object */ + ecma_value_t pattern_value, /**< pattern */ + uint16_t flags) /**< flags */ +{ + ecma_string_t *pattern_str_p = ecma_regexp_read_pattern_str_helper (pattern_value); + + if (JERRY_UNLIKELY (pattern_str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + const re_compiled_code_t *bc_p = NULL; + + ecma_value_t ret_value = re_compile_bytecode (&bc_p, pattern_str_p, flags); + + ecma_deref_ecma_string (pattern_str_p); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + return ret_value; + } + + JERRY_ASSERT (ecma_is_value_empty (ret_value)); + + ecma_op_regexp_initialize (regexp_obj_p, bc_p, pattern_str_p, flags); + + return ecma_make_object_value (regexp_obj_p); +} /* ecma_op_create_regexp_with_flags */ /** * Canonicalize a character @@ -1249,7 +1388,7 @@ ecma_regexp_exec_helper (ecma_object_t *regexp_object_p, /**< RegExp object */ { ecma_value_t ret_value = ECMA_VALUE_EMPTY; - JERRY_ASSERT (ecma_object_class_is (regexp_object_p, LIT_MAGIC_STRING_REGEXP_UL)); + JERRY_ASSERT (ecma_object_is_regexp_object (ecma_make_object_value (regexp_object_p))); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) regexp_object_p; re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, @@ -2439,7 +2578,6 @@ ecma_regexp_replace_helper (ecma_value_t this_arg, /**< this argument */ { ecma_extended_object_t *function_p = (ecma_extended_object_t *) ecma_get_object_from_value (result); if (ecma_object_class_is (this_obj_p, LIT_MAGIC_STRING_REGEXP_UL) - && !ecma_builtin_is (this_obj_p, ECMA_BUILTIN_ID_REGEXP_PROTOTYPE) && ecma_builtin_is_regexp_exec (function_p)) { result = ecma_op_object_get_by_magic_id (this_obj_p, LIT_MAGIC_STRING_STICKY); diff --git a/jerry-core/ecma/operations/ecma-regexp-object.h b/jerry-core/ecma/operations/ecma-regexp-object.h index 6ae10f388..bea4c0925 100644 --- a/jerry-core/ecma/operations/ecma-regexp-object.h +++ b/jerry-core/ecma/operations/ecma-regexp-object.h @@ -97,22 +97,30 @@ typedef struct uint16_t flags; /**< RegExp flags */ } ecma_regexp_ctx_t; -ecma_value_t ecma_op_create_regexp_object_from_bytecode (re_compiled_code_t *bytecode_p); -ecma_value_t ecma_op_create_regexp_object (ecma_string_t *pattern_p, uint16_t flags); +ecma_object_t *ecma_op_regexp_alloc (ecma_object_t *new_target_obj_p); ecma_value_t ecma_regexp_exec_helper (ecma_object_t *regexp_object_p, ecma_string_t *input_string_p); ecma_string_t *ecma_regexp_read_pattern_str_helper (ecma_value_t pattern_arg); lit_code_point_t ecma_regexp_canonicalize (lit_code_point_t ch, bool is_ignorecase); lit_code_point_t ecma_regexp_canonicalize_char (lit_code_point_t ch); ecma_value_t ecma_regexp_parse_flags (ecma_string_t *flags_str_p, uint16_t *flags_p); -void ecma_regexp_initialize_props (ecma_object_t *re_obj_p, ecma_string_t *source_p, uint16_t flags); - +void ecma_regexp_create_and_initialize_props (ecma_object_t *re_object_p, + ecma_string_t *source_p, + uint16_t flags); ecma_value_t ecma_regexp_replace_helper (ecma_value_t this_arg, ecma_value_t string_arg, ecma_value_t replace_arg); ecma_value_t ecma_regexp_search_helper (ecma_value_t regexp_arg, ecma_value_t string_arg); ecma_value_t ecma_regexp_split_helper (ecma_value_t this_arg, ecma_value_t string_arg, ecma_value_t limit_arg); ecma_value_t ecma_regexp_match_helper (ecma_value_t this_arg, ecma_value_t string_arg); ecma_value_t ecma_op_regexp_exec (ecma_value_t this_arg, ecma_string_t *str_p); + +ecma_value_t ecma_op_create_regexp_from_bytecode (ecma_object_t *regexp_obj_p, re_compiled_code_t *bc_p); +ecma_value_t ecma_op_create_regexp_from_pattern (ecma_object_t *regexp_obj_p, + ecma_value_t pattern_value, + ecma_value_t flags_value); +ecma_value_t ecma_op_create_regexp_with_flags (ecma_object_t *regexp_obj_p, + ecma_value_t pattern_value, + uint16_t flags); /** * @} * @} diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h index 6ca3f91ed..fe5f72cc0 100644 --- a/jerry-core/lit/lit-magic-strings.h +++ b/jerry-core/lit/lit-magic-strings.h @@ -51,6 +51,7 @@ typedef enum LIT_INTERNAL_MAGIC_API_INTERNAL, /**< Property key used to add non-visible JS properties from the public API */ LIT_INTERNAL_MAGIC_STRING_ARRAY_PROTOTYPE_VALUES, /**< %ArrayProto_values% intrinsic routine */ LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE, /**< FunctionEnvironmentRecord [[ThisBindingValue]] internal slot */ + LIT_INTERNAL_MAGIC_STRING_REGEXP_PROTO, /**< RegExp object prototype */ /* List of well known symbols */ LIT_GLOBAL_SYMBOL_HAS_INSTANCE, /**< @@hasInstance well known symbol */ LIT_GLOBAL_SYMBOL_IS_CONCAT_SPREADABLE, /**< @@isConcatSpreadable well known symbol */ diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index d39bb549d..e9e54ab32 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -440,16 +440,14 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ #if ENABLED (JERRY_BUILTIN_REGEXP) if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) { - ecma_value_t ret_value; - ret_value = ecma_op_create_regexp_object_from_bytecode ((re_compiled_code_t *) bytecode_p); + ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL); - if (ECMA_IS_VALUE_ERROR (ret_value)) + if (JERRY_UNLIKELY (regexp_obj_p == NULL)) { - /* TODO: throw exception instead of define an 'undefined' value. */ - return ECMA_VALUE_UNDEFINED; + return ECMA_VALUE_ERROR; } - return ret_value; + return ecma_op_create_regexp_from_bytecode (regexp_obj_p, (re_compiled_code_t *) bytecode_p);; } #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ diff --git a/tests/jerry/es2015/regexp-construct.js b/tests/jerry/es2015/regexp-construct.js index 199a3327d..0c0d86344 100644 --- a/tests/jerry/es2015/regexp-construct.js +++ b/tests/jerry/es2015/regexp-construct.js @@ -14,12 +14,18 @@ var r = RegExp ("a","gim"); var r2 = RegExp (r,"gim"); +var r3 = RegExp (r); assert(r2.source === 'a'); assert(r2.global === true); assert(r2.ignoreCase === true); assert(r2.multiline === true); +assert(r3.source === 'a'); +assert(r3.global === true); +assert(r3.ignoreCase === true); +assert(r3.multiline === true); + var obj = { get source() { throw 5 }, [Symbol.match] : true } try {