summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/regexp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/regexp')
-rw-r--r--js/src/jit-test/tests/regexp/RegExpExec-errors.js6
-rw-r--r--js/src/jit-test/tests/regexp/bug1419785.js3
-rw-r--r--js/src/jit-test/tests/regexp/bug1445907.js14
-rw-r--r--js/src/jit-test/tests/regexp/bug1600272.js6
-rw-r--r--js/src/jit-test/tests/regexp/bug1640473.js16
-rw-r--r--js/src/jit-test/tests/regexp/bug1640475.js9
-rw-r--r--js/src/jit-test/tests/regexp/bug1640479.js15
-rw-r--r--js/src/jit-test/tests/regexp/bug1640487.js8
-rw-r--r--js/src/jit-test/tests/regexp/bug1640592.js2
-rw-r--r--js/src/jit-test/tests/regexp/bug1697077.js11
-rw-r--r--js/src/jit-test/tests/regexp/bug1703750.js7
-rw-r--r--js/src/jit-test/tests/regexp/bug1718842-1.js7
-rw-r--r--js/src/jit-test/tests/regexp/bug1718842-2.js9
-rw-r--r--js/src/jit-test/tests/regexp/bug1783555.js4
-rw-r--r--js/src/jit-test/tests/regexp/bug1783830.js7
-rw-r--r--js/src/jit-test/tests/regexp/bug1786012.js8
-rw-r--r--js/src/jit-test/tests/regexp/bug1794317.js7
-rw-r--r--js/src/jit-test/tests/regexp/builtin-exec-wrapper.js7
-rw-r--r--js/src/jit-test/tests/regexp/clone-statics.js21
-rw-r--r--js/src/jit-test/tests/regexp/flag-getters.js61
-rw-r--r--js/src/jit-test/tests/regexp/huge-01.js21
-rw-r--r--js/src/jit-test/tests/regexp/huge-02.js13
-rw-r--r--js/src/jit-test/tests/regexp/lastIndex-negative.js14
-rw-r--r--js/src/jit-test/tests/regexp/lastIndex-non-writable.js71
-rw-r--r--js/src/jit-test/tests/regexp/lastIndex-too-large.js13
-rw-r--r--js/src/jit-test/tests/regexp/lastIndex-valueOf.js16
-rw-r--r--js/src/jit-test/tests/regexp/match-indices-dictionary.js20
-rw-r--r--js/src/jit-test/tests/regexp/match-indices-warp.js8
-rw-r--r--js/src/jit-test/tests/regexp/named-capture-proxy.js21
-rw-r--r--js/src/jit-test/tests/regexp/non-unicode-case-folding-backreference.js67
-rw-r--r--js/src/jit-test/tests/regexp/non-unicode-case-folding.js68
-rw-r--r--js/src/jit-test/tests/regexp/replace-exec.js12
-rw-r--r--js/src/jit-test/tests/regexp/rope-inputs.js10
-rw-r--r--js/src/jit-test/tests/regexp/unicode-back-reference.js3
34 files changed, 585 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/regexp/RegExpExec-errors.js b/js/src/jit-test/tests/regexp/RegExpExec-errors.js
new file mode 100644
index 0000000000..bee579859f
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/RegExpExec-errors.js
@@ -0,0 +1,6 @@
+load(libdir + "asserts.js");
+
+assertErrorMessage(() => RegExp.prototype.test.call({}), TypeError,
+ /test method called on incompatible Object/);
+assertErrorMessage(() => RegExp.prototype[Symbol.match].call([]), TypeError,
+ /\[Symbol\.match\] method called on incompatible Array/);
diff --git a/js/src/jit-test/tests/regexp/bug1419785.js b/js/src/jit-test/tests/regexp/bug1419785.js
new file mode 100644
index 0000000000..b40eca9f8c
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1419785.js
@@ -0,0 +1,3 @@
+// |jit-test| error:character class
+Object.defineProperty(RegExp.prototype, Symbol.search, {get: () => { throw "wrong"; }});
+"abc".search("[[");
diff --git a/js/src/jit-test/tests/regexp/bug1445907.js b/js/src/jit-test/tests/regexp/bug1445907.js
new file mode 100644
index 0000000000..a0e0dca57b
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1445907.js
@@ -0,0 +1,14 @@
+// |jit-test| skip-if: !wasmDebuggingEnabled()
+
+// On ARM64, we failed to save x28 properly when generating code for the regexp
+// matcher.
+//
+// There's wasm and Debugger code here because the combination forces the use of
+// x28 and exposes the bug when running on the simulator.
+
+var g = newGlobal({newCompartment: true});
+var dbg = new Debugger(g);
+g.eval(`var m = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func (export "test")))')))`);
+var re = /./;
+dbg.onEnterFrame = function(frame) { re.exec("x") };
+result = g.eval("m.exports.test()");
diff --git a/js/src/jit-test/tests/regexp/bug1600272.js b/js/src/jit-test/tests/regexp/bug1600272.js
new file mode 100644
index 0000000000..08f154f771
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1600272.js
@@ -0,0 +1,6 @@
+// |jit-test| skip-if: helperThreadCount() === 0
+evalInWorker(`
+ Array.prototype[1] = 1;
+ var source = Array(50000).join("(") + "a" + Array(50000).join(")");
+ var r70 = RegExp(source);
+`);
diff --git a/js/src/jit-test/tests/regexp/bug1640473.js b/js/src/jit-test/tests/regexp/bug1640473.js
new file mode 100644
index 0000000000..710ece3fc2
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1640473.js
@@ -0,0 +1,16 @@
+// |jit-test| skip-if: getBuildConfiguration()['wasi']
+var s = "";
+var input = "";
+for (var i = 0; i < 500; ++i) {
+ s += "(?<a" + i + ">a)";
+ s += "(?<b" + i + ">b)?";
+ input += "a";
+}
+
+var r = RegExp(s);
+var e = r.exec(input);
+
+for (var i = 0; i < 500; i++) {
+ assertEq(e.groups["a" + i], "a");
+ assertEq(e.groups["b" + i], undefined);
+}
diff --git a/js/src/jit-test/tests/regexp/bug1640475.js b/js/src/jit-test/tests/regexp/bug1640475.js
new file mode 100644
index 0000000000..58c092ec1d
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1640475.js
@@ -0,0 +1,9 @@
+// |jit-test| skip-if: !('oomTest' in this)
+
+var i = 0;
+oomTest(function() {
+ for (var j = 0; j < 10; ++j) {
+ var r = RegExp(`(?<_${(i++).toString(32)}>a)`);
+ r.exec("a");
+ }
+});
diff --git a/js/src/jit-test/tests/regexp/bug1640479.js b/js/src/jit-test/tests/regexp/bug1640479.js
new file mode 100644
index 0000000000..ff166d6451
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1640479.js
@@ -0,0 +1,15 @@
+// |jit-test| skip-if: !('oomTest' in this)
+
+var failures = 0;
+var i = 0;
+
+function foo() {
+ var e;
+ var r = RegExp("(?<_" + (i++) + "a>)");
+ try { e = r.exec("a"); } catch {}
+ e = r.exec("a");
+ if (e.groups === undefined) failures++;
+}
+
+oomTest(foo);
+assertEq(failures, 0);
diff --git a/js/src/jit-test/tests/regexp/bug1640487.js b/js/src/jit-test/tests/regexp/bug1640487.js
new file mode 100644
index 0000000000..7ee3756075
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1640487.js
@@ -0,0 +1,8 @@
+var re = /(?<x>a)|b/;
+
+function f(j) {
+ var s = String.fromCharCode(0x61 + (j === 1));
+ var e = re.exec(s);
+ if (e.groups.x !== "a") print(i,j);
+}
+for (var i = 0; i < 2; ++i) f(i);
diff --git a/js/src/jit-test/tests/regexp/bug1640592.js b/js/src/jit-test/tests/regexp/bug1640592.js
new file mode 100644
index 0000000000..e00fd81e99
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1640592.js
@@ -0,0 +1,2 @@
+gczeal(14, 16);
+"a".match(/(?<a>a)/);
diff --git a/js/src/jit-test/tests/regexp/bug1697077.js b/js/src/jit-test/tests/regexp/bug1697077.js
new file mode 100644
index 0000000000..3d43ae60a2
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1697077.js
@@ -0,0 +1,11 @@
+// |jit-test| skip-if: !('interruptRegexp' in this)
+var s0 = "A".repeat(10*1024);
+var interrupted = false;
+gczeal(0);
+setInterruptCallback(() => {
+ interrupted = true;
+ startgc(7,'shrinking');
+ return true;
+});
+assertEq(interruptRegexp(/a(bc|bd)/, s0), null);
+assertEq(interrupted, true); \ No newline at end of file
diff --git a/js/src/jit-test/tests/regexp/bug1703750.js b/js/src/jit-test/tests/regexp/bug1703750.js
new file mode 100644
index 0000000000..4be2d7748a
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1703750.js
@@ -0,0 +1,7 @@
+function foo() {
+ const b = "".match();
+ try {
+ foo();
+ } catch {}
+}
+foo()
diff --git a/js/src/jit-test/tests/regexp/bug1718842-1.js b/js/src/jit-test/tests/regexp/bug1718842-1.js
new file mode 100644
index 0000000000..35b557b6b4
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1718842-1.js
@@ -0,0 +1,7 @@
+var g = newGlobal({sameZoneAs: this});
+
+var re1 = RegExp("(?<a>a)");
+var re2 = g.RegExp("(?<a>a)");
+
+re1.exec("a");
+re2.exec("a");
diff --git a/js/src/jit-test/tests/regexp/bug1718842-2.js b/js/src/jit-test/tests/regexp/bug1718842-2.js
new file mode 100644
index 0000000000..88f76046f7
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1718842-2.js
@@ -0,0 +1,9 @@
+var g = newGlobal();
+
+g.enableTrackAllocations();
+
+var re1 = RegExp("(?<a>a)");
+var re2 = g.RegExp("(?<a>a)");
+
+re1.exec("a");
+re2.exec("a");
diff --git a/js/src/jit-test/tests/regexp/bug1783555.js b/js/src/jit-test/tests/regexp/bug1783555.js
new file mode 100644
index 0000000000..60978910a2
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1783555.js
@@ -0,0 +1,4 @@
+var src = "(.?)".repeat(65536);
+try {
+ "".match(src);
+} catch {}
diff --git a/js/src/jit-test/tests/regexp/bug1783830.js b/js/src/jit-test/tests/regexp/bug1783830.js
new file mode 100644
index 0000000000..cd41be7f66
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1783830.js
@@ -0,0 +1,7 @@
+assertEq(/[^!]/u.exec('\u{1F4A9}')[0], "\u{1F4A9}");
+assertEq(/^[^!]/u.exec('\u{1F4A9}')[0], "\u{1F4A9}");
+assertEq(/[^!]$/u.exec('\u{1F4A9}')[0], "\u{1F4A9}");
+assertEq(/![^!]/u.exec('!\u{1F4A9}')[0], "!\u{1F4A9}");
+assertEq(/[^!]!/u.exec('\u{1F4A9}!')[0], "\u{1F4A9}!");
+assertEq(/![^!]/ui.exec('!\u{1F4A9}')[0], "!\u{1F4A9}");
+assertEq(/[^!]!/ui.exec('\u{1F4A9}!')[0], "\u{1F4A9}!");
diff --git a/js/src/jit-test/tests/regexp/bug1786012.js b/js/src/jit-test/tests/regexp/bug1786012.js
new file mode 100644
index 0000000000..f806fd22bb
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1786012.js
@@ -0,0 +1,8 @@
+var repeated = "A".repeat(65536);
+var src = "^(?:" + repeated + ")\$";
+
+for (var i = 0; i < 100; i++) {
+ try {
+ RegExp(src).test();
+ } catch {}
+}
diff --git a/js/src/jit-test/tests/regexp/bug1794317.js b/js/src/jit-test/tests/regexp/bug1794317.js
new file mode 100644
index 0000000000..1ecb21eb64
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/bug1794317.js
@@ -0,0 +1,7 @@
+// |jit-test| skip-if: !('oomTest' in this)
+
+for (let i = 0; i < 2; i++) {
+ oomTest(function () {
+ RegExp("(?<name" + i + ">)").exec();
+ })
+}
diff --git a/js/src/jit-test/tests/regexp/builtin-exec-wrapper.js b/js/src/jit-test/tests/regexp/builtin-exec-wrapper.js
new file mode 100644
index 0000000000..63660de643
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/builtin-exec-wrapper.js
@@ -0,0 +1,7 @@
+var g = newGlobal({newCompartment: true});
+g.evaluate(`RegExp.prototype.exec = {};`);
+var wrapper = g.evaluate(`/abc.+def/`);
+assertEq(RegExp.prototype.test.call(wrapper, "abc"), false);
+assertEq(RegExp.prototype.test.call(wrapper, "abcXdef"), true);
+assertEq(RegExp.prototype[Symbol.match].call(wrapper, "abc"), null);
+assertEq(RegExp.prototype[Symbol.match].call(wrapper, "abcXdef")[0], "abcXdef");
diff --git a/js/src/jit-test/tests/regexp/clone-statics.js b/js/src/jit-test/tests/regexp/clone-statics.js
new file mode 100644
index 0000000000..d2f0ce1cac
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/clone-statics.js
@@ -0,0 +1,21 @@
+// |jit-test| skip-if: helperThreadCount() === 0
+
+offThreadCompileToStencil(`
+ function foo(x, {}) {
+ do {
+ re = /erwe/;
+ if (x === 1)
+ re.x = 1;
+ else
+ re.x = "a";
+ assertEq(re.x.length, (x === 1) ? undefined : 1);
+ } while (!inIon());
+ }
+
+ foo(0, 0);
+ RegExp.multiline = 1;
+ foo(1, 0);
+`);
+
+var stencil = finishOffThreadStencil();
+evalStencil(stencil);
diff --git a/js/src/jit-test/tests/regexp/flag-getters.js b/js/src/jit-test/tests/regexp/flag-getters.js
new file mode 100644
index 0000000000..fbc1ad7274
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/flag-getters.js
@@ -0,0 +1,61 @@
+// Test inlining for RegExp flag getters.
+
+function testGlobal() {
+ const xs = [/a/, /b/g];
+
+ for (let i = 0; i < 200; ++i) {
+ let x = xs[i & 1];
+ assertEq(x.global, !!(i & 1));
+ }
+}
+for (let i = 0; i < 2; ++i) testGlobal();
+
+function testIgnoreCase() {
+ const xs = [/a/, /b/i];
+
+ for (let i = 0; i < 200; ++i) {
+ let x = xs[i & 1];
+ assertEq(x.ignoreCase, !!(i & 1));
+ }
+}
+for (let i = 0; i < 2; ++i) testIgnoreCase();
+
+function testMultiline() {
+ const xs = [/a/, /b/m];
+
+ for (let i = 0; i < 200; ++i) {
+ let x = xs[i & 1];
+ assertEq(x.multiline, !!(i & 1));
+ }
+}
+for (let i = 0; i < 2; ++i) testMultiline();
+
+function testDotAll() {
+ const xs = [/a/, /b/s];
+
+ for (let i = 0; i < 200; ++i) {
+ let x = xs[i & 1];
+ assertEq(x.dotAll, !!(i & 1));
+ }
+}
+for (let i = 0; i < 2; ++i) testDotAll();
+
+function testUnicode() {
+ const xs = [/a/, /b/u];
+
+ for (let i = 0; i < 200; ++i) {
+ let x = xs[i & 1];
+ assertEq(x.unicode, !!(i & 1));
+ }
+}
+for (let i = 0; i < 2; ++i) testUnicode();
+
+function testSticky() {
+ const xs = [/a/, /b/y];
+
+ for (let i = 0; i < 200; ++i) {
+ let x = xs[i & 1];
+ assertEq(x.sticky, !!(i & 1));
+ }
+}
+for (let i = 0; i < 2; ++i) testSticky();
diff --git a/js/src/jit-test/tests/regexp/huge-01.js b/js/src/jit-test/tests/regexp/huge-01.js
new file mode 100644
index 0000000000..bc1529f0c6
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/huge-01.js
@@ -0,0 +1,21 @@
+
+function g(N, p) {
+ var prefix = p.repeat(N);
+ var str = prefix + "[AB]";
+
+ try {
+ var re = new RegExp(str);
+ re.exec(prefix + "A");
+ } catch(e) {
+ // 1. Regexp too big is raised by the lack of the 64k virtual registers
+ // reserved for the regexp evaluation.
+ // 2. The stack overflow can occur during the analysis of the regexp
+ assertEq(e.message.includes("regexp too big") ||
+ e.message.includes("Stack overflow") ||
+ e.message.includes("too much recursion"), true);
+ }
+}
+
+var prefix = "/(?=k)ok/";
+for (var i = 0; i < 18; i++)
+ g(Math.pow(2, i), prefix)
diff --git a/js/src/jit-test/tests/regexp/huge-02.js b/js/src/jit-test/tests/regexp/huge-02.js
new file mode 100644
index 0000000000..1d0d94e10c
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/huge-02.js
@@ -0,0 +1,13 @@
+var interestingCaptureNums = [(1 << 14),
+ (1 << 15) - 1,
+ (1 << 15),
+ (1 << 15) + 1,
+ (1 << 16)]
+
+for (let i of interestingCaptureNums) {
+ print(i);
+ try {
+ var source = Array(i).join("(") + "a" + Array(i).join(")");
+ RegExp(source).exec("a");
+ } catch {}
+}
diff --git a/js/src/jit-test/tests/regexp/lastIndex-negative.js b/js/src/jit-test/tests/regexp/lastIndex-negative.js
new file mode 100644
index 0000000000..536b3d2233
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/lastIndex-negative.js
@@ -0,0 +1,14 @@
+// A negative lastIndex value must be treated as 0.
+function test() {
+ var re = /abc.+de/g;
+ for (var i = 0; i < 100; i++) {
+ re.lastIndex = (i > 60) ? -1 : 0;
+ assertEq(typeof re.exec("abcXdef"), "object");
+ assertEq(re.lastIndex, 6);
+
+ re.lastIndex = (i > 60) ? -1 : 0;
+ assertEq(re.test("abcXdef"), true);
+ assertEq(re.lastIndex, 6);
+ }
+}
+test();
diff --git a/js/src/jit-test/tests/regexp/lastIndex-non-writable.js b/js/src/jit-test/tests/regexp/lastIndex-non-writable.js
new file mode 100644
index 0000000000..74839762f5
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/lastIndex-non-writable.js
@@ -0,0 +1,71 @@
+function testGlobalExec() {
+ var re = /abc.+de/g;
+ var c = 0;
+ for (var i = 0; i < 100; i++) {
+ re.lastIndex = 0;
+ if (i === 60) {
+ Object.freeze(re);
+ }
+ try {
+ re.exec("abcXdef");
+ } catch (e) {
+ assertEq(e.toString().includes("lastIndex"), true);
+ c++;
+ }
+ assertEq(re.lastIndex, i >= 60 ? 0 : 6);
+ }
+ assertEq(c, 40);
+}
+testGlobalExec();
+
+function testStickyTest() {
+ var re = /abc.+de/y;
+ var c = 0;
+ for (var i = 0; i < 100; i++) {
+ re.lastIndex = 0;
+ if (i === 60) {
+ Object.freeze(re);
+ }
+ try {
+ re.test("abcXdef");
+ } catch (e) {
+ assertEq(e.toString().includes("lastIndex"), true);
+ c++;
+ }
+ assertEq(re.lastIndex, i >= 60 ? 0 : 6);
+ }
+ assertEq(c, 40);
+}
+testStickyTest();
+
+// Must not reset too-large .lastIndex to 0 if non-writable.
+function testLastIndexOutOfRange() {
+ var re = /abc.+de/g;
+ re.lastIndex = 123;
+ Object.freeze(re);
+ for (var i = 0; i < 100; i++) {
+ var ex = null;
+ try {
+ re.exec("abcXdef");
+ } catch (e) {
+ ex = e;
+ }
+ assertEq(ex.toString().includes("lastIndex"), true);
+ assertEq(re.lastIndex, 123);
+ }
+}
+testLastIndexOutOfRange();
+
+// .lastIndex is ignored for non-global/non-sticky regexps.
+function testPlainExec() {
+ var re = /abc.+de/;
+ re.lastIndex = 1234;
+ for (var i = 0; i < 100; i++) {
+ if (i === 60) {
+ Object.freeze(re);
+ }
+ assertEq(re.exec("abcXdef")[0], "abcXde");
+ assertEq(re.lastIndex, 1234);
+ }
+}
+testPlainExec();
diff --git a/js/src/jit-test/tests/regexp/lastIndex-too-large.js b/js/src/jit-test/tests/regexp/lastIndex-too-large.js
new file mode 100644
index 0000000000..3e04042dd0
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/lastIndex-too-large.js
@@ -0,0 +1,13 @@
+function test() {
+ var re = /abc.+de/y;
+ for (var i = 0; i < 100; i++) {
+ re.lastIndex = 10;
+ assertEq(re.exec("abcXdef"), null);
+ assertEq(re.lastIndex, 0);
+
+ re.lastIndex = 10;
+ assertEq(re.test("abcXdef"), false);
+ assertEq(re.lastIndex, 0);
+ }
+}
+test();
diff --git a/js/src/jit-test/tests/regexp/lastIndex-valueOf.js b/js/src/jit-test/tests/regexp/lastIndex-valueOf.js
new file mode 100644
index 0000000000..3794d20c2e
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/lastIndex-valueOf.js
@@ -0,0 +1,16 @@
+function test() {
+ var re = /abc.+de/g;
+ var c = 0;
+ var weird = {valueOf() { c++; return 0; }};
+ for (var i = 0; i < 100; i++) {
+ re.lastIndex = (i > 60) ? weird : 0;
+ assertEq(typeof re.exec("abcXdef"), "object");
+ assertEq(re.lastIndex, 6);
+
+ re.lastIndex = (i > 60) ? weird : 0;
+ assertEq(re.test("abcXdef"), true);
+ assertEq(re.lastIndex, 6);
+ }
+ assertEq(c, 78);
+}
+test();
diff --git a/js/src/jit-test/tests/regexp/match-indices-dictionary.js b/js/src/jit-test/tests/regexp/match-indices-dictionary.js
new file mode 100644
index 0000000000..e0cb5993f5
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/match-indices-dictionary.js
@@ -0,0 +1,20 @@
+// |jit-test| skip-if: getBuildConfiguration()['wasi']
+var s = "";
+var input = "";
+for (var i = 0; i < 500; ++i) {
+ s += "(?<a" + i + ">a)";
+ s += "(?<b" + i + ">b)?";
+ input += "a";
+}
+
+var r = RegExp(s, "d");
+var e = r.exec(input);
+
+for (var i = 0; i < 500; i++) {
+ assertEq(e.groups["a" + i], "a");
+ assertEq(e.groups["b" + i], undefined);
+
+ assertEq(e.indices.groups["a" + i][0], i)
+ assertEq(e.indices.groups["a" + i][1], i + 1)
+ assertEq(e.indices.groups["b" + i], undefined)
+}
diff --git a/js/src/jit-test/tests/regexp/match-indices-warp.js b/js/src/jit-test/tests/regexp/match-indices-warp.js
new file mode 100644
index 0000000000..634d368aee
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/match-indices-warp.js
@@ -0,0 +1,8 @@
+var re = /A*(B)A*/d;
+for (var i = 0; i < 100; i++) {
+ var match = re.exec("xxxxxAAABAxxxxx");
+ assertEq(match.indices[0][0], 5);
+ assertEq(match.indices[0][1], 10);
+ assertEq(match.indices[1][0], 8);
+ assertEq(match.indices[1][1], 9);
+}
diff --git a/js/src/jit-test/tests/regexp/named-capture-proxy.js b/js/src/jit-test/tests/regexp/named-capture-proxy.js
new file mode 100644
index 0000000000..e7cc933850
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/named-capture-proxy.js
@@ -0,0 +1,21 @@
+var access_log = "";
+const handler = {
+ get: function(obj, prop) {
+ access_log += prop + ",";
+ return prop in obj ? obj[prop] : "<filled by proxy>";
+ }
+};
+
+class ProxiedGroupRegExp extends RegExp {
+ exec(s) {
+ var result = super.exec(s);
+ if (result) {
+ result.groups = new Proxy(result.groups, handler);
+ }
+ return result;
+ }
+}
+
+let re = new ProxiedGroupRegExp("(?<x>.)");
+assertEq("a".replace(re, "$<x> $<y>"), "a <filled by proxy>");
+assertEq(access_log, "x,y,")
diff --git a/js/src/jit-test/tests/regexp/non-unicode-case-folding-backreference.js b/js/src/jit-test/tests/regexp/non-unicode-case-folding-backreference.js
new file mode 100644
index 0000000000..bfea5f89a9
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/non-unicode-case-folding-backreference.js
@@ -0,0 +1,67 @@
+// |jit-test| skip-if: typeof Intl === 'undefined'
+
+// See https://tc39.es/ecma262/#sec-runtime-semantics-canonicalize-ch
+function Canonicalize(ch) {
+ var u = ch.toUpperCase();
+ if (u.length > 1) return ch;
+ var cu = u.charCodeAt(0);
+ if (ch.charCodeAt(0) >= 128 && cu < 128) return ch;
+ return cu;
+}
+
+function TestEquivalenceClass(eclass) {
+ var backref = /(.)\1/i;
+
+ for (var i = 0; i < eclass.length; i++) {
+ for (var j = 0; j < eclass.length; j++) {
+ if (i == j) continue;
+ var c1 = eclass[i];
+ var c2 = eclass[j];
+ var cc = c1 + c2;
+ var shouldMatch = Canonicalize(c1) === Canonicalize(c2);
+
+ assertEq(backref.test(cc), shouldMatch);
+ }
+ }
+}
+
+function TestAll() {
+ for (var eclass of equivalence_classes) {
+ TestEquivalenceClass(eclass);
+ }
+}
+
+// Interesting case-folding equivalence classes (as determined by
+// ICU's UnicodeSet::closeOver). A class is interesting if it contains
+// more than two characters, or if it contains any characters in
+// IgnoreSet or SpecialAddSet as defined in new-regexp/special-case.h.
+var equivalence_classes = [
+ '\u0041\u0061', // Aa (sanity check)
+ '\u004b\u006b\u212a', // KkK
+ '\u0053\u0073\u017f', // Ssſ
+ '\u00b5\u039c\u03bc', // µΜμ
+ '\u00c5\u00e5\u212b', // ÅåÅ
+ '\u00df\u1e9e', // ßẞ
+ '\u03a9\u03c9\u2126', // ΩωΩ
+ '\u0390\u1fd3', // ΐΐ
+ '\u0398\u03b8\u03d1\u03f4', // Θθϑϴ
+ '\u03b0\u1fe3', // ΰΰ
+ '\u1f80\u1f88', // ᾀᾈ
+ '\u1fb3\u1fbc', // ᾳᾼ
+ '\u1fc3\u1fcc', // ῃῌ
+ '\u1ff3\u1ffc', // ῳῼ
+ '\ufb05\ufb06', // ſtst
+
+ // Everything below this line is a well-behaved case-folding
+ // equivalence class with more than two characters but only one
+ // canonical case-folded character
+ '\u01c4\u01c5\u01c6', '\u01c7\u01c8\u01c9', '\u01ca\u01cb\u01cc',
+ '\u01f1\u01f2\u01f3', '\u0345\u0399\u03b9\u1fbe', '\u0392\u03b2\u03d0',
+ '\u0395\u03b5\u03f5', '\u039a\u03ba\u03f0', '\u03a0\u03c0\u03d6',
+ '\u03a1\u03c1\u03f1', '\u03a3\u03c2\u03c3', '\u03a6\u03c6\u03d5',
+ '\u0412\u0432\u1c80', '\u0414\u0434\u1c81', '\u041e\u043e\u1c82',
+ '\u0421\u0441\u1c83', '\u0422\u0442\u1c84\u1c85', '\u042a\u044a\u1c86',
+ '\u0462\u0463\u1c87', '\u1c88\ua64a\ua64b', '\u1e60\u1e61\u1e9b'
+];
+
+TestAll();
diff --git a/js/src/jit-test/tests/regexp/non-unicode-case-folding.js b/js/src/jit-test/tests/regexp/non-unicode-case-folding.js
new file mode 100644
index 0000000000..52a799238e
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/non-unicode-case-folding.js
@@ -0,0 +1,68 @@
+// |jit-test| skip-if: typeof Intl === 'undefined'
+
+// See https://tc39.es/ecma262/#sec-runtime-semantics-canonicalize-ch
+function Canonicalize(ch) {
+ var u = ch.toUpperCase();
+ if (u.length > 1) return ch;
+ var cu = u.charCodeAt(0);
+ if (ch.charCodeAt(0) >= 128 && cu < 128) return ch;
+ return cu;
+}
+
+function TestEquivalenceClass(eclass) {
+ for (var i = 0; i < eclass.length; i++) {
+ for (var j = 0; j < eclass.length; j++) {
+ if (i == j) continue;
+ var c1 = eclass[i];
+ var c2 = eclass[j];
+ var shouldMatch = Canonicalize(c1) === Canonicalize(c2);
+
+ var re1 = new RegExp(c1, 'i');
+ var re2 = new RegExp('[' + c1 + ']', 'i');
+
+ assertEq(re1.test(c2), shouldMatch);
+ assertEq(re2.test(c2), shouldMatch);
+ }
+ }
+}
+
+function TestAll() {
+ for (var eclass of equivalence_classes) {
+ TestEquivalenceClass(eclass);
+ }
+}
+
+// Interesting case-folding equivalence classes (as determined by
+// ICU's UnicodeSet::closeOver). A class is interesting if it contains
+// more than two characters, or if it contains any characters in
+// IgnoreSet or SpecialAddSet as defined in new-regexp/special-case.h.
+var equivalence_classes = [
+ '\u0041\u0061', // Aa (sanity check)
+ '\u004b\u006b\u212a', // KkK
+ '\u0053\u0073\u017f', // Ssſ
+ '\u00b5\u039c\u03bc', // µΜμ
+ '\u00c5\u00e5\u212b', // ÅåÅ
+ '\u00df\u1e9e', // ßẞ
+ '\u03a9\u03c9\u2126', // ΩωΩ
+ '\u0390\u1fd3', // ΐΐ
+ '\u0398\u03b8\u03d1\u03f4', // Θθϑϴ
+ '\u03b0\u1fe3', // ΰΰ
+ '\u1f80\u1f88', // ᾀᾈ
+ '\u1fb3\u1fbc', // ᾳᾼ
+ '\u1fc3\u1fcc', // ῃῌ
+ '\u1ff3\u1ffc', // ῳῼ
+ '\ufb05\ufb06', // ſtst
+
+ // Everything below this line is a well-behaved case-folding
+ // equivalence class with more than two characters but only one
+ // canonical case-folded character
+ '\u01c4\u01c5\u01c6', '\u01c7\u01c8\u01c9', '\u01ca\u01cb\u01cc',
+ '\u01f1\u01f2\u01f3', '\u0345\u0399\u03b9\u1fbe', '\u0392\u03b2\u03d0',
+ '\u0395\u03b5\u03f5', '\u039a\u03ba\u03f0', '\u03a0\u03c0\u03d6',
+ '\u03a1\u03c1\u03f1', '\u03a3\u03c2\u03c3', '\u03a6\u03c6\u03d5',
+ '\u0412\u0432\u1c80', '\u0414\u0434\u1c81', '\u041e\u043e\u1c82',
+ '\u0421\u0441\u1c83', '\u0422\u0442\u1c84\u1c85', '\u042a\u044a\u1c86',
+ '\u0462\u0463\u1c87', '\u1c88\ua64a\ua64b', '\u1e60\u1e61\u1e9b'
+];
+
+TestAll();
diff --git a/js/src/jit-test/tests/regexp/replace-exec.js b/js/src/jit-test/tests/regexp/replace-exec.js
new file mode 100644
index 0000000000..b6488ec678
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/replace-exec.js
@@ -0,0 +1,12 @@
+function test() {
+ var re = /abc.+de/;
+ var c = 0;
+ for (var i = 0; i < 100; i++) {
+ assertEq(re.test("abcXdef"), true);
+ if (i === 60) {
+ RegExp.prototype.exec = () => { c++; return {}; };
+ }
+ }
+ assertEq(c, 39);
+}
+test();
diff --git a/js/src/jit-test/tests/regexp/rope-inputs.js b/js/src/jit-test/tests/regexp/rope-inputs.js
new file mode 100644
index 0000000000..d8f4b4de94
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/rope-inputs.js
@@ -0,0 +1,10 @@
+function test() {
+ var re = /abc(.+)z/;
+ for (var i = 0; i < 100; i++) {
+ assertEq(re.exec(newRope("abcd", "xyz"))[1], "dxy");
+ assertEq(re.test(newRope("abcd", "xyz")), true);
+ assertEq(re[Symbol.search](newRope(".abcd", "xyz")), 1);
+ assertEq(re[Symbol.match](newRope("abcd", "xyz"))[1], "dxy");
+ }
+}
+test();
diff --git a/js/src/jit-test/tests/regexp/unicode-back-reference.js b/js/src/jit-test/tests/regexp/unicode-back-reference.js
new file mode 100644
index 0000000000..90eef410a5
--- /dev/null
+++ b/js/src/jit-test/tests/regexp/unicode-back-reference.js
@@ -0,0 +1,3 @@
+for (var t = 0; t < 10000; t++) {
+ (t + "\u1234").split(/(.)\1/i);
+}