diff --git a/jerry-core/ecma/operations/ecma-regexp-object.c b/jerry-core/ecma/operations/ecma-regexp-object.c index 31b9fd859..8f3732a8b 100644 --- a/jerry-core/ecma/operations/ecma-regexp-object.c +++ b/jerry-core/ecma/operations/ecma-regexp-object.c @@ -1921,7 +1921,7 @@ ecma_regexp_search_helper (ecma_value_t regexp_arg, /**< regexp argument */ ecma_value_t result = ECMA_VALUE_ERROR; - /* 3-4. */ + /* 3. */ ecma_string_t *const string_p = ecma_op_to_string (string_arg); if (string_p == NULL) { @@ -1930,7 +1930,7 @@ ecma_regexp_search_helper (ecma_value_t regexp_arg, /**< regexp argument */ ecma_object_t *const regexp_object_p = ecma_get_object_from_value (regexp_arg); - /* 5-6. */ + /* 4. */ ecma_string_t *const last_index_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); const ecma_value_t prev_last_index = ecma_op_object_get (regexp_object_p, last_index_str_p); if (ECMA_IS_VALUE_ERROR (prev_last_index)) @@ -1938,35 +1938,56 @@ ecma_regexp_search_helper (ecma_value_t regexp_arg, /**< regexp argument */ goto cleanup_string; } - /* 7-8. */ - const ecma_value_t status = ecma_op_object_put (regexp_object_p, last_index_str_p, ecma_make_uint32_value (0), true); - if (ECMA_IS_VALUE_ERROR (status)) + /* 5. */ + if (prev_last_index != ecma_make_uint32_value (0)) { - ecma_free_value (prev_last_index); - goto cleanup_string; + const ecma_value_t status = ecma_op_object_put (regexp_object_p, + last_index_str_p, + ecma_make_uint32_value (0), + true); + + if (ECMA_IS_VALUE_ERROR (status)) + { + goto cleanup_prev_last_index; + } + + JERRY_ASSERT (ecma_is_value_boolean (status)); } - JERRY_ASSERT (ecma_is_value_boolean (status)); - - /* 9-10. */ + /* 6. */ const ecma_value_t match = ecma_op_regexp_exec (regexp_arg, string_p); if (ECMA_IS_VALUE_ERROR (match)) { - ecma_free_value (prev_last_index); - goto cleanup_string; + goto cleanup_prev_last_index; } - /* 11-12. */ - result = ecma_op_object_put (regexp_object_p, last_index_str_p, prev_last_index, true); - ecma_free_value (prev_last_index); - - if (ECMA_IS_VALUE_ERROR (result)) + /* 7. */ + const ecma_value_t current_last_index = ecma_op_object_get (regexp_object_p, last_index_str_p); + if (ECMA_IS_VALUE_ERROR (current_last_index)) { ecma_free_value (match); - goto cleanup_string; + goto cleanup_prev_last_index; } - /* 13-14. */ + const bool same_value = ecma_op_same_value (prev_last_index, current_last_index); + + ecma_free_value (current_last_index); + + /* 8. */ + if (!same_value) + { + result = ecma_op_object_put (regexp_object_p, last_index_str_p, prev_last_index, true); + + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_free_value (match); + goto cleanup_prev_last_index; + } + + JERRY_ASSERT (ecma_is_value_boolean (result)); + } + + /* 9-10. */ if (ecma_is_value_null (match)) { result = ecma_make_int32_value (-1); @@ -1978,6 +1999,9 @@ ecma_regexp_search_helper (ecma_value_t regexp_arg, /**< regexp argument */ ecma_deref_object (match_p); } +cleanup_prev_last_index: + ecma_free_value (prev_last_index); + cleanup_string: ecma_deref_ecma_string (string_p); return result; diff --git a/tests/jerry/es.next/symbol-search.js b/tests/jerry/es.next/symbol-search.js index 5f664d5e8..dd8d9cc19 100644 --- a/tests/jerry/es.next/symbol-search.js +++ b/tests/jerry/es.next/symbol-search.js @@ -226,3 +226,70 @@ o = { } assert (RegExp.prototype[Symbol.search].call (o, "str") === 0); + +var r = /a/; +r.lastIndex = 3.14; + +var get_calls = []; +var set_calls = []; + +var handler = { + get: function(o, k) { + get_calls.push(k); + + if (k === "exec") { + return (str) => r.exec(str); + } + + return r[k]; + }, + set: function(o, k, v) { + set_calls.push(k); + r[k] = v; + } +}; + +var p = new Proxy(r, handler); +assert (search.call(p, "bba") === 2); + +assert (get_calls.join(",") === "lastIndex,exec,lastIndex"); +assert (set_calls.join(",") === "lastIndex,lastIndex"); +assert (r.lastIndex === 3.14); + +var o = { + get lastIndex() { + Object.defineProperty(o, "lastIndex", { + get: function () { throw "abrupt get second lastIndex"; } + }); + return 1; + }, + set lastIndex(v) {}, + exec: () => { return null; } +} + +try { + search.call(o, "str"); + assert (false); +} catch (e) { + assert (e === "abrupt get second lastIndex"); +} + +var index = 1; +var o = { + get lastIndex() { + return index++; + }, + set lastIndex(v) { + Object.defineProperty(o, "lastIndex", { + set: function (v) { throw "abrupt set second lastIndex"; } + }); + }, + exec: () => { return null; } +} + +try { + search.call(o, "str"); + assert (false); +} catch (e) { + assert (e === "abrupt set second lastIndex"); +} diff --git a/tests/test262-es6-excludelist.xml b/tests/test262-es6-excludelist.xml index 95031e99c..30ad9c783 100644 --- a/tests/test262-es6-excludelist.xml +++ b/tests/test262-es6-excludelist.xml @@ -378,4 +378,6 @@ Unicode 13: 0x180E is no longer whitespace character Unicode 13: 0x180E is no longer whitespace character Unicode 13: 0x180E is no longer whitespace character + lastIndex handling in Symbol.search has changed since ES6 + lastIndex handling in Symbol.search has changed since ES6