Title: [227107] trunk
Revision
227107
Author
utatane....@gmail.com
Date
2018-01-17 20:17:32 -0800 (Wed, 17 Jan 2018)

Log Message

[DFG][FTL] Introduce PhantomNewRegexp and RegExpExecNonGlobalOrSticky
https://bugs.webkit.org/show_bug.cgi?id=181535

Reviewed by Saam Barati.

JSTests:

* stress/inserted-recovery-with-set-last-index.js: Added.
(shouldBe):
(foo):
* stress/materialize-regexp-at-osr-exit.js: Added.
(shouldBe):
(test):
* stress/materialize-regexp-cyclic-regexp-at-osr-exit.js: Added.
(shouldBe):
(test):
* stress/materialize-regexp-cyclic-regexp.js: Added.
(shouldBe):
(test):
(i.switch):
* stress/materialize-regexp-cyclic.js: Added.
(shouldBe):
(test):
(i.switch):
* stress/materialize-regexp-referenced-from-phantom-regexp-cyclic.js: Added.
(bar):
(foo):
(test):
* stress/materialize-regexp-referenced-from-phantom-regexp.js: Added.
(bar):
(foo):
(test):
* stress/materialize-regexp.js: Added.
(shouldBe):
(test):
* stress/phantom-regexp-regexp-exec.js: Added.
(shouldBe):
(test):
* stress/phantom-regexp-string-match.js: Added.
(shouldBe):
(test):
* stress/regexp-last-index-sinking.js: Added.
(shouldBe):
(test):

Source/_javascript_Core:

When executing the code like `string.match(/regexp/)`, `/regexp/` object is created every time we execute this code.
However, user rarely cares about this `/regexp/` object. Typically, it is soon discarded even if it has `lastIndex`
information. So we should not create RegExpObject for this typical case.

This patch introduces PhantomNewRegexp. We convert NewRegexp node to PhantomNewRegexp in Object Allocation Sinking (OAS)
phase. We should do this analysis in OAS phase since we track modifications to `lastIndex` in the OAS phase. Even if
`lastIndex` is modified, it may not be read by users. So we have a chance to drop this NewRegexp beacause we carefully model
SetRegExpObjectLastIndex and GetRegExpObjectLastIndex in OAS phase.

This patch is a first attempt to drop NewRegexp. So we start optimizing it with the simple step: we first drop RegExp with
non-global and non-sticky one. We can later extend this optimization for RegExp with global flag. But this is not included
in this patch.

We convert RegExpExec to RegExpExecNonGlobalOrSticky if we find that the given RegExpObject's RegExp is not global/sticky
flagged. Since we do not need to touch `lastIndex` property in this case, RegExpExecNonGlobalOrSticky just takes RegExp
instead of RegExpObject. This offers the chance to make NewRegExp unused.

We also convert RegExpMatchFast to RegExpExecNonGlobalOrSticky if its RegExpObject's RegExp is non-global and non-sticky,
since they are the same behavior.

The above optimization completely removes NewRegexp in SixSpeed's regexp-u.{es5,es6}. The resulted execution time is
somewhat pure execution time of our Yarr implementation.

                             baseline                  patched

    regex-u.es5          34.8557+-0.5963     ^      6.1507+-0.5526        ^ definitely 5.6670x faster
    regex-u.es6          89.1919+-3.3851     ^     32.0917+-0.4260        ^ definitely 2.7793x faster

This patch does not change Octane/RegExp so much since it heavily uses String.prototype.replace, which is not handled in
this patch right now. We should support StringReplace node in subsequent patches.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGClobbersExitState.cpp:
(JSC::DFG::clobbersExitState):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGMayExit.cpp:
* dfg/DFGNode.cpp:
(JSC::DFG::Node::convertToRegExpExecNonGlobalOrSticky):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToPhantomNewRegexp):
(JSC::DFG::Node::convertToSetRegExpObjectLastIndex):
(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasCellOperand):
(JSC::DFG::Node::isPhantomAllocation):
(JSC::DFG::Node::hasIgnoreLastIndexIsWritable):
(JSC::DFG::Node::ignoreLastIndexIsWritable):
* dfg/DFGNodeType.h:
* dfg/DFGObjectAllocationSinkingPhase.cpp:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGPromotedHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGPromotedHeapLocation.h:
(JSC::DFG::PromotedLocationDescriptor::neededForMaterialization const):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileNewRegexp):
(JSC::DFG::SpeculativeJIT::compileSetRegExpObjectLastIndex):
(JSC::DFG::SpeculativeJIT::compileRegExpExecNonGlobalOrSticky):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
* dfg/DFGValidate.cpp:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileRegExpExecNonGlobalOrSticky):
(JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
(JSC::FTL::DFG::LowerDFGToB3::compileSetRegExpObjectLastIndex):
* ftl/FTLOperations.cpp:
(JSC::FTL::operationPopulateObjectInOSR):
(JSC::FTL::operationMaterializeObjectInOSR):
* jit/JITOperations.h:
* runtime/RegExpObject.h:
(JSC::RegExpObject::create):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (227106 => 227107)


--- trunk/JSTests/ChangeLog	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/JSTests/ChangeLog	2018-01-18 04:17:32 UTC (rev 227107)
@@ -1,3 +1,48 @@
+2018-01-17  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [DFG][FTL] Introduce PhantomNewRegexp and RegExpExecNonGlobalOrSticky
+        https://bugs.webkit.org/show_bug.cgi?id=181535
+
+        Reviewed by Saam Barati.
+
+        * stress/inserted-recovery-with-set-last-index.js: Added.
+        (shouldBe):
+        (foo):
+        * stress/materialize-regexp-at-osr-exit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/materialize-regexp-cyclic-regexp-at-osr-exit.js: Added.
+        (shouldBe):
+        (test):
+        * stress/materialize-regexp-cyclic-regexp.js: Added.
+        (shouldBe):
+        (test):
+        (i.switch):
+        * stress/materialize-regexp-cyclic.js: Added.
+        (shouldBe):
+        (test):
+        (i.switch):
+        * stress/materialize-regexp-referenced-from-phantom-regexp-cyclic.js: Added.
+        (bar):
+        (foo):
+        (test):
+        * stress/materialize-regexp-referenced-from-phantom-regexp.js: Added.
+        (bar):
+        (foo):
+        (test):
+        * stress/materialize-regexp.js: Added.
+        (shouldBe):
+        (test):
+        * stress/phantom-regexp-regexp-exec.js: Added.
+        (shouldBe):
+        (test):
+        * stress/phantom-regexp-string-match.js: Added.
+        (shouldBe):
+        (test):
+        * stress/regexp-last-index-sinking.js: Added.
+        (shouldBe):
+        (test):
+
 2018-01-17  Saam Barati  <sbar...@apple.com>
 
         Disable Atomics when SharedArrayBuffer isn’t enabled

Added: trunk/JSTests/stress/inserted-recovery-with-set-last-index.js (0 => 227107)


--- trunk/JSTests/stress/inserted-recovery-with-set-last-index.js	                        (rev 0)
+++ trunk/JSTests/stress/inserted-recovery-with-set-last-index.js	2018-01-18 04:17:32 UTC (rev 227107)
@@ -0,0 +1,28 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function foo(p) {
+    var o = /Hello/;
+    if (p) {
+        var res = /World/;
+        res.lastIndex = o;
+        return res;
+    }
+}
+
+noInline(foo);
+
+var array = new Array(1000);
+for (var i = 0; i < 4000000; ++i) {
+    var o = foo(i & 0x1);
+    if (i & 0x1) {
+        shouldBe(o instanceof RegExp, true);
+        shouldBe(o.toString(), "/World/");
+        shouldBe(o.lastIndex.toString(), "/Hello/");
+    }
+    array[i % array.length] = o;
+}
+

Added: trunk/JSTests/stress/materialize-regexp-at-osr-exit.js (0 => 227107)


--- trunk/JSTests/stress/materialize-regexp-at-osr-exit.js	                        (rev 0)
+++ trunk/JSTests/stress/materialize-regexp-at-osr-exit.js	2018-01-18 04:17:32 UTC (rev 227107)
@@ -0,0 +1,24 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(flag)
+{
+    var regexp = /hello world/;
+    regexp.lastIndex = "Cocoa";
+    if (flag) {
+        OSRExit();
+        return regexp;
+    }
+    return regexp.lastIndex;
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i)
+    shouldBe(test(false), "Cocoa");
+
+var regexp = test(true);
+shouldBe(regexp instanceof RegExp, true);
+shouldBe(regexp.lastIndex, "Cocoa");

Added: trunk/JSTests/stress/materialize-regexp-cyclic-regexp-at-osr-exit.js (0 => 227107)


--- trunk/JSTests/stress/materialize-regexp-cyclic-regexp-at-osr-exit.js	                        (rev 0)
+++ trunk/JSTests/stress/materialize-regexp-cyclic-regexp-at-osr-exit.js	2018-01-18 04:17:32 UTC (rev 227107)
@@ -0,0 +1,28 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(num)
+{
+    var regexp = /hello world/;
+    var world = /World/;
+    regexp.lastIndex = world;
+    world.lastIndex = regexp;
+    if (num === 0) {
+        OSRExit();
+        return regexp;
+    }
+    return 42;
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(test(1), 42);
+
+var regexp = test(0);
+shouldBe(regexp instanceof RegExp, true);
+shouldBe(regexp.toString(), "/hello world/");
+shouldBe(regexp.lastIndex instanceof RegExp, true);
+shouldBe(regexp.lastIndex.toString(), "/World/");

Added: trunk/JSTests/stress/materialize-regexp-cyclic-regexp.js (0 => 227107)


--- trunk/JSTests/stress/materialize-regexp-cyclic-regexp.js	                        (rev 0)
+++ trunk/JSTests/stress/materialize-regexp-cyclic-regexp.js	2018-01-18 04:17:32 UTC (rev 227107)
@@ -0,0 +1,46 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(num)
+{
+    var regexp = /hello world/;
+    var world = /World/;
+    regexp.lastIndex = world;
+    world.lastIndex = regexp;
+    if (num === 0)
+        return regexp;
+    if (num === 1)
+        return regexp.lastIndex;
+    return regexp.lastIndex.lastIndex;
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i) {
+    var num = i % 3;
+    switch (num) {
+    case 0:
+        var regexp = test(num);
+        shouldBe(regexp instanceof RegExp, true);
+        shouldBe(regexp.toString(), "/hello world/");
+        shouldBe(regexp.lastIndex instanceof RegExp, true);
+        shouldBe(regexp.lastIndex.toString(), "/World/");
+        break;
+    case 1:
+        var regexp = test(num);
+        shouldBe(regexp instanceof RegExp, true);
+        shouldBe(regexp.toString(), "/World/");
+        shouldBe(regexp.lastIndex instanceof RegExp, true);
+        shouldBe(regexp.lastIndex.toString(), "/hello world/");
+        break;
+    case 2:
+        var regexp = test(num);
+        shouldBe(regexp instanceof RegExp, true);
+        shouldBe(regexp.toString(), "/hello world/");
+        shouldBe(regexp.lastIndex instanceof RegExp, true);
+        shouldBe(regexp.lastIndex.toString(), "/World/");
+        break;
+    }
+}

Added: trunk/JSTests/stress/materialize-regexp-cyclic.js (0 => 227107)


--- trunk/JSTests/stress/materialize-regexp-cyclic.js	                        (rev 0)
+++ trunk/JSTests/stress/materialize-regexp-cyclic.js	2018-01-18 04:17:32 UTC (rev 227107)
@@ -0,0 +1,39 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(num)
+{
+    var regexp = /hello world/;
+    regexp.lastIndex = { ok: regexp, value: 42 };
+    if (num === 0)
+        return regexp;
+    if (num === 1)
+        return regexp.lastIndex;
+    return regexp.lastIndex.value;
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i) {
+    var num = i % 3;
+    switch (num) {
+    case 0:
+        var regexp = test(num);
+        shouldBe(regexp instanceof RegExp, true);
+        shouldBe(typeof regexp.lastIndex, "object");
+        shouldBe(regexp.lastIndex.ok, regexp);
+        break;
+    case 1:
+        var object = test(num);
+        shouldBe(object.value, 42);
+        shouldBe(object.ok instanceof RegExp, true);
+        shouldBe(object.ok.lastIndex, object);
+        break;
+    case 2:
+        var value = test(num);
+        shouldBe(value, 42);
+        break;
+    }
+}

Added: trunk/JSTests/stress/materialize-regexp-referenced-from-phantom-regexp-cyclic.js (0 => 227107)


--- trunk/JSTests/stress/materialize-regexp-referenced-from-phantom-regexp-cyclic.js	                        (rev 0)
+++ trunk/JSTests/stress/materialize-regexp-referenced-from-phantom-regexp-cyclic.js	2018-01-18 04:17:32 UTC (rev 227107)
@@ -0,0 +1,43 @@
+function bar()
+{
+}
+
+noInline(bar);
+
+function foo(p, x)
+{
+    var a = /Hello/;
+    a.lastIndex = 1;
+    var b = /World/;
+    b.lastIndex = a;
+    var c = /World/;
+    c.lastIndex = a;
+    var d = /Cocoa/;
+    d.lastIndex = c;
+    a.lastIndex = d;
+
+    if (!p)
+        return 0;
+
+    bar(b);
+
+    x += 2000000000;
+
+    c.lastIndex.lastIndex = 42;
+    return b.lastIndex.lastIndex;
+}
+
+noInline(foo);
+
+function test(x)
+{
+    var result = foo(true, x);
+    if (result != 42)
+        throw "Error: bad result: " + result;
+}
+
+for (var i = 0; i < 100000; ++i)
+    test(0);
+
+test(2000000000);
+

Added: trunk/JSTests/stress/materialize-regexp-referenced-from-phantom-regexp.js (0 => 227107)


--- trunk/JSTests/stress/materialize-regexp-referenced-from-phantom-regexp.js	                        (rev 0)
+++ trunk/JSTests/stress/materialize-regexp-referenced-from-phantom-regexp.js	2018-01-18 04:17:32 UTC (rev 227107)
@@ -0,0 +1,40 @@
+function bar()
+{
+}
+
+noInline(bar);
+
+function foo(p, x)
+{
+    var a = /Hello/;
+    a.lastIndex = 1;
+    var b = /World/;
+    b.lastIndex = a;
+    var c = /World/;
+    c.lastIndex = a;
+
+    if (!p)
+        return 0;
+
+    bar(b);
+
+    x += 2000000000;
+
+    c.lastIndex.lastIndex = 42;
+    return b.lastIndex.lastIndex;
+}
+
+noInline(foo);
+
+function test(x)
+{
+    var result = foo(true, x);
+    if (result != 42)
+        throw "Error: bad result: " + result;
+}
+
+for (var i = 0; i < 100000; ++i)
+    test(0);
+
+test(2000000000);
+

Added: trunk/JSTests/stress/materialize-regexp.js (0 => 227107)


--- trunk/JSTests/stress/materialize-regexp.js	                        (rev 0)
+++ trunk/JSTests/stress/materialize-regexp.js	2018-01-18 04:17:32 UTC (rev 227107)
@@ -0,0 +1,24 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(flag)
+{
+    var regexp = /hello world/;
+    regexp.lastIndex = "Cocoa";
+    if (flag)
+        return regexp;
+    return regexp.lastIndex;
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i) {
+    if (i & 0x1) {
+        var regexp = test(true);
+        shouldBe(regexp instanceof RegExp, true);
+        shouldBe(regexp.lastIndex, "Cocoa");
+    } else
+        shouldBe(test(false), "Cocoa");
+}

Added: trunk/JSTests/stress/phantom-regexp-regexp-exec.js (0 => 227107)


--- trunk/JSTests/stress/phantom-regexp-regexp-exec.js	                        (rev 0)
+++ trunk/JSTests/stress/phantom-regexp-regexp-exec.js	2018-01-18 04:17:32 UTC (rev 227107)
@@ -0,0 +1,26 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(string, flag)
+{
+    var regexp = /oa/;
+    var result = regexp.exec(string);
+    if (flag)
+        return regexp;
+    return result;
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i) {
+    if (i & 1) {
+        var result = test("Cocoa", true);
+        shouldBe(result instanceof RegExp, true);
+    } else {
+        var result = test("Cocoa", false);
+        shouldBe(result.input, "Cocoa");
+        shouldBe(result[0], "oa");
+    }
+}

Added: trunk/JSTests/stress/phantom-regexp-string-match.js (0 => 227107)


--- trunk/JSTests/stress/phantom-regexp-string-match.js	                        (rev 0)
+++ trunk/JSTests/stress/phantom-regexp-string-match.js	2018-01-18 04:17:32 UTC (rev 227107)
@@ -0,0 +1,26 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(string, flag)
+{
+    var regexp = /oa/;
+    var result = string.match(regexp);
+    if (flag)
+        return regexp;
+    return result;
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i) {
+    if (i & 1) {
+        var result = test("Cocoa", true);
+        shouldBe(result instanceof RegExp, true);
+    } else {
+        var result = test("Cocoa", false);
+        shouldBe(result.input, "Cocoa");
+        shouldBe(result[0], "oa");
+    }
+}

Added: trunk/JSTests/stress/regexp-last-index-sinking.js (0 => 227107)


--- trunk/JSTests/stress/regexp-last-index-sinking.js	                        (rev 0)
+++ trunk/JSTests/stress/regexp-last-index-sinking.js	2018-01-18 04:17:32 UTC (rev 227107)
@@ -0,0 +1,23 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(num)
+{
+    var regexp = /regexp/;
+    if (num & 1)
+        regexp.lastIndex = 42;
+    else
+        regexp.lastIndex = 2;
+    return regexp.lastIndex;
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i) {
+    if (i & 1)
+        shouldBe(test(i), 42);
+    else
+        shouldBe(test(i), 2);
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (227106 => 227107)


--- trunk/Source/_javascript_Core/ChangeLog	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-01-18 04:17:32 UTC (rev 227107)
@@ -1,5 +1,106 @@
 2018-01-17  Yusuke Suzuki  <utatane....@gmail.com>
 
+        [DFG][FTL] Introduce PhantomNewRegexp and RegExpExecNonGlobalOrSticky
+        https://bugs.webkit.org/show_bug.cgi?id=181535
+
+        Reviewed by Saam Barati.
+
+        When executing the code like `string.match(/regexp/)`, `/regexp/` object is created every time we execute this code.
+        However, user rarely cares about this `/regexp/` object. Typically, it is soon discarded even if it has `lastIndex`
+        information. So we should not create RegExpObject for this typical case.
+
+        This patch introduces PhantomNewRegexp. We convert NewRegexp node to PhantomNewRegexp in Object Allocation Sinking (OAS)
+        phase. We should do this analysis in OAS phase since we track modifications to `lastIndex` in the OAS phase. Even if
+        `lastIndex` is modified, it may not be read by users. So we have a chance to drop this NewRegexp beacause we carefully model
+        SetRegExpObjectLastIndex and GetRegExpObjectLastIndex in OAS phase.
+
+        This patch is a first attempt to drop NewRegexp. So we start optimizing it with the simple step: we first drop RegExp with
+        non-global and non-sticky one. We can later extend this optimization for RegExp with global flag. But this is not included
+        in this patch.
+
+        We convert RegExpExec to RegExpExecNonGlobalOrSticky if we find that the given RegExpObject's RegExp is not global/sticky
+        flagged. Since we do not need to touch `lastIndex` property in this case, RegExpExecNonGlobalOrSticky just takes RegExp
+        instead of RegExpObject. This offers the chance to make NewRegExp unused.
+
+        We also convert RegExpMatchFast to RegExpExecNonGlobalOrSticky if its RegExpObject's RegExp is non-global and non-sticky,
+        since they are the same behavior.
+
+        The above optimization completely removes NewRegexp in SixSpeed's regexp-u.{es5,es6}. The resulted execution time is
+        somewhat pure execution time of our Yarr implementation.
+
+                                     baseline                  patched
+
+            regex-u.es5          34.8557+-0.5963     ^      6.1507+-0.5526        ^ definitely 5.6670x faster
+            regex-u.es6          89.1919+-3.3851     ^     32.0917+-0.4260        ^ definitely 2.7793x faster
+
+        This patch does not change Octane/RegExp so much since it heavily uses String.prototype.replace, which is not handled in
+        this patch right now. We should support StringReplace node in subsequent patches.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGClobbersExitState.cpp:
+        (JSC::DFG::clobbersExitState):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGMayExit.cpp:
+        * dfg/DFGNode.cpp:
+        (JSC::DFG::Node::convertToRegExpExecNonGlobalOrSticky):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToPhantomNewRegexp):
+        (JSC::DFG::Node::convertToSetRegExpObjectLastIndex):
+        (JSC::DFG::Node::hasHeapPrediction):
+        (JSC::DFG::Node::hasCellOperand):
+        (JSC::DFG::Node::isPhantomAllocation):
+        (JSC::DFG::Node::hasIgnoreLastIndexIsWritable):
+        (JSC::DFG::Node::ignoreLastIndexIsWritable):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGObjectAllocationSinkingPhase.cpp:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGPromotedHeapLocation.cpp:
+        (WTF::printInternal):
+        * dfg/DFGPromotedHeapLocation.h:
+        (JSC::DFG::PromotedLocationDescriptor::neededForMaterialization const):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileNewRegexp):
+        (JSC::DFG::SpeculativeJIT::compileSetRegExpObjectLastIndex):
+        (JSC::DFG::SpeculativeJIT::compileRegExpExecNonGlobalOrSticky):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStrengthReductionPhase.cpp:
+        (JSC::DFG::StrengthReductionPhase::handleNode):
+        * dfg/DFGValidate.cpp:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileRegExpExecNonGlobalOrSticky):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
+        (JSC::FTL::DFG::LowerDFGToB3::compileSetRegExpObjectLastIndex):
+        * ftl/FTLOperations.cpp:
+        (JSC::FTL::operationPopulateObjectInOSR):
+        (JSC::FTL::operationMaterializeObjectInOSR):
+        * jit/JITOperations.h:
+        * runtime/RegExpObject.h:
+        (JSC::RegExpObject::create):
+
+2018-01-17  Yusuke Suzuki  <utatane....@gmail.com>
+
         [FTL] Remove unused helper functions to convert node to PutHint
         https://bugs.webkit.org/show_bug.cgi?id=181775
 

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2018-01-18 04:17:32 UTC (rev 227107)
@@ -1935,11 +1935,15 @@
     }
             
     case RegExpExec:
-        if (node->child2().useKind() == RegExpObjectUse
-            && node->child3().useKind() == StringUse) {
-            // This doesn't clobber the world since there are no conversions to perform.
-        } else
-            clobberWorld(node->origin.semantic, clobberLimit);
+    case RegExpExecNonGlobalOrSticky:
+        if (node->op() == RegExpExec) {
+            if (node->child2().useKind() == RegExpObjectUse
+                && node->child3().useKind() == StringUse) {
+                // This doesn't clobber the world since there are no conversions to perform.
+            } else
+                clobberWorld(node->origin.semantic, clobberLimit);
+        }
+
         if (JSValue globalObjectValue = forNode(node->child1()).m_value) {
             if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(m_vm, globalObjectValue)) {
                 if (!globalObject->isHavingABadTime()) {
@@ -2254,6 +2258,7 @@
     case PhantomSpread:
     case PhantomNewArrayWithSpread:
     case PhantomNewArrayBuffer:
+    case PhantomNewRegexp:
     case BottomValue:
         m_state.setDidClobber(true); // Prevent constant folding.
         // This claims to return bottom.

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -4499,7 +4499,7 @@
         case op_new_regexp: {
             RegExp* regexp = m_inlineStackTop->m_codeBlock->regexp(currentInstruction[2].u.operand);
             FrozenValue* frozen = m_graph.freezeStrong(regexp);
-            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewRegexp, OpInfo(frozen)));
+            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewRegexp, OpInfo(frozen), jsConstant(jsNumber(0))));
             NEXT_OPCODE(op_new_regexp);
         }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2018-01-18 04:17:32 UTC (rev 227107)
@@ -1475,6 +1475,7 @@
     case PhantomNewAsyncGeneratorFunction:
     case PhantomCreateActivation:
     case MaterializeCreateActivation:
+    case PhantomNewRegexp:
         read(HeapObjectCount);
         write(HeapObjectCount);
         return;
@@ -1504,6 +1505,11 @@
         write(Heap);
         return;
 
+    case RegExpExecNonGlobalOrSticky:
+        read(RegExpState);
+        write(RegExpState);
+        return;
+
     case StringReplace:
     case StringReplaceRegExp:
         if (node->child1().useKind() == StringUse

Modified: trunk/Source/_javascript_Core/dfg/DFGClobbersExitState.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGClobbersExitState.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGClobbersExitState.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -67,6 +67,7 @@
     case PhantomNewAsyncFunction:
     case PhantomCreateActivation:
     case MaterializeCreateActivation:
+    case PhantomNewRegexp:
     case CountExecution:
     case SuperSamplerBegin:
     case SuperSamplerEnd:

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -137,6 +137,7 @@
     case AssertNotEmpty:
     case CheckStringIdent:
     case RegExpExec:
+    case RegExpExecNonGlobalOrSticky:
     case RegExpTest:
     case RegExpMatchFast:
     case CompareLess:
@@ -272,6 +273,7 @@
     case PhantomNewArrayBuffer:
     case PhantomSpread:
     case PhantomClonedArguments:
+    case PhantomNewRegexp:
     case GetMyArgumentByVal:
     case GetMyArgumentByValOutOfBounds:
     case ForwardVarargs:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -1443,7 +1443,7 @@
                 
                 if (uid == vm().propertyNames->lastIndex.impl()
                     && node->child1()->shouldSpeculateRegExpObject()) {
-                    node->setOp(SetRegExpObjectLastIndex);
+                    node->convertToSetRegExpObjectLastIndex();
                     fixEdge<RegExpObjectUse>(node->child1());
                     speculateForBarrier(node->child2());
                     break;
@@ -1651,6 +1651,7 @@
         case PhantomNewArrayWithSpread:
         case PhantomNewArrayBuffer:
         case PhantomClonedArguments:
+        case PhantomNewRegexp:
         case GetMyArgumentByVal:
         case GetMyArgumentByValOutOfBounds:
         case GetVectorLength:
@@ -1667,6 +1668,7 @@
         case GetRegExpObjectLastIndex:
         case SetRegExpObjectLastIndex:
         case RecordRegExpCachedResult:
+        case RegExpExecNonGlobalOrSticky:
             // These are just nodes that we don't currently expect to see during fixup.
             // If we ever wanted to insert them prior to fixup, then we just have to create
             // fixup rules for them.

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -346,6 +346,8 @@
         out.print(comma, "id", data->identifierNumber, "{", identifiers()[data->identifierNumber], "}");
         out.print(", domJIT = ", RawPointer(data->domJIT));
     }
+    if (node->hasIgnoreLastIndexIsWritable())
+        out.print(comma, "ignoreLastIndexIsWritable = ", node->ignoreLastIndexIsWritable());
     if (node->isConstant())
         out.print(comma, pointerDumpInContext(node->constant(), context));
     if (node->isJump())

Modified: trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -118,9 +118,15 @@
     case NewStringObject:
     case NewRegexp:
     case ToNumber:
+    case RegExpExecNonGlobalOrSticky:
         result = ExitsForExceptions;
         break;
 
+    case SetRegExpObjectLastIndex:
+        if (node->ignoreLastIndexIsWritable())
+            break;
+        return Exits;
+
     default:
         // If in doubt, return true.
         return Exits;

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGNode.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -209,6 +209,16 @@
         clearFlags(NodeMustGenerate);
 }
 
+void Node::convertToRegExpExecNonGlobalOrSticky(FrozenValue* regExp)
+{
+    ASSERT(op() == RegExpExec);
+    setOpAndDefaultFlags(RegExpExecNonGlobalOrSticky);
+    children.child1() = Edge(children.child1().node(), KnownCellUse);
+    children.child2() = Edge(children.child3().node(), StringUse);
+    children.child3() = Edge();
+    m_opInfo = regExp;
+}
+
 String Node::tryGetString(Graph& graph)
 {
     if (hasConstant())

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2018-01-18 04:17:32 UTC (rev 227107)
@@ -648,6 +648,15 @@
         children = AdjacencyList();
     }
 
+    void convertToPhantomNewRegexp()
+    {
+        ASSERT(m_op == NewRegexp);
+        setOpAndDefaultFlags(PhantomNewRegexp);
+        m_opInfo = OpInfoWrapper();
+        m_opInfo2 = OpInfoWrapper();
+        children = AdjacencyList();
+    }
+
     void convertPhantomToPhantomLocal()
     {
         ASSERT(m_op == Phantom && (child1()->op() == Phi || child1()->op() == SetLocal || child1()->op() == SetArgument));
@@ -727,6 +736,14 @@
     void convertToDirectCall(FrozenValue*);
 
     void convertToCallDOM(Graph&);
+
+    void convertToRegExpExecNonGlobalOrSticky(FrozenValue* regExp);
+
+    void convertToSetRegExpObjectLastIndex()
+    {
+        setOp(SetRegExpObjectLastIndex);
+        m_opInfo = false;
+    }
     
     JSValue asJSValue()
     {
@@ -1563,6 +1580,7 @@
         case ArrayPop:
         case ArrayPush:
         case RegExpExec:
+        case RegExpExecNonGlobalOrSticky:
         case RegExpTest:
         case RegExpMatchFast:
         case GetGlobalVar:
@@ -1645,6 +1663,7 @@
         case DirectTailCall:
         case DirectConstruct:
         case DirectTailCallInlinedCaller:
+        case RegExpExecNonGlobalOrSticky:
             return true;
         default:
             return false;
@@ -1909,6 +1928,7 @@
         case PhantomNewAsyncFunction:
         case PhantomNewAsyncGeneratorFunction:
         case PhantomCreateActivation:
+        case PhantomNewRegexp:
             return true;
         default:
             return false;
@@ -2654,6 +2674,17 @@
         return m_opInfo.as<int32_t>();
     }
 
+    bool hasIgnoreLastIndexIsWritable()
+    {
+        return op() == SetRegExpObjectLastIndex;
+    }
+
+    bool ignoreLastIndexIsWritable()
+    {
+        ASSERT(hasIgnoreLastIndexIsWritable());
+        return m_opInfo.as<uint32_t>();
+    }
+
     uint32_t errorType()
     {
         ASSERT(op() == ThrowStaticError);

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2018-01-18 04:17:32 UTC (rev 227107)
@@ -268,6 +268,7 @@
     \
     /* Optimizations for regular _expression_ matching. */\
     macro(RegExpExec, NodeResultJS | NodeMustGenerate) \
+    macro(RegExpExecNonGlobalOrSticky, NodeResultJS) \
     macro(RegExpTest, NodeResultJS | NodeMustGenerate) \
     macro(RegExpMatchFast, NodeResultJS | NodeMustGenerate) \
     macro(StringReplace, NodeResultJS | NodeMustGenerate) \
@@ -332,6 +333,7 @@
     macro(PhantomNewAsyncGeneratorFunction, NodeResultJS | NodeMustGenerate) \
     macro(PhantomCreateActivation, NodeResultJS | NodeMustGenerate) \
     macro(MaterializeCreateActivation, NodeResultJS | NodeHasVarArgs) \
+    macro(PhantomNewRegexp, NodeResultJS | NodeMustGenerate) \
     \
     /* Nodes for misc operations. */\
     macro(OverridesHasInstance, NodeMustGenerate | NodeResultBoolean) \

Modified: trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -141,7 +141,7 @@
     // once it is escaped if it still has pointers to it in order to
     // replace any use of those pointers by the corresponding
     // materialization
-    enum class Kind { Escaped, Object, Activation, Function, GeneratorFunction, AsyncFunction, AsyncGeneratorFunction };
+    enum class Kind { Escaped, Object, Activation, Function, GeneratorFunction, AsyncFunction, AsyncGeneratorFunction, RegExpObject };
 
     using Fields = HashMap<PromotedLocationDescriptor, Node*>;
 
@@ -246,6 +246,11 @@
         return m_kind == Kind::Function || m_kind == Kind::GeneratorFunction || m_kind == Kind::AsyncFunction;
     }
 
+    bool isRegExpObjectAllocation() const
+    {
+        return m_kind == Kind::RegExpObject;
+    }
+
     bool operator==(const Allocation& other) const
     {
         return m_identifier == other.m_identifier
@@ -290,9 +295,14 @@
         case Kind::AsyncGeneratorFunction:
             out.print("AsyncGeneratorFunction");
             break;
+
         case Kind::Activation:
             out.print("Activation");
             break;
+
+        case Kind::RegExpObject:
+            out.print("RegExpObject");
+            break;
         }
         out.print("Allocation(");
         if (!m_structures.isEmpty())
@@ -849,6 +859,14 @@
             break;
         }
 
+        case NewRegexp: {
+            target = &m_heap.newAllocation(node, Allocation::Kind::RegExpObject);
+
+            writes.add(RegExpObjectRegExpPLoc, LazyNode(node->cellOperand()));
+            writes.add(RegExpObjectLastIndexPLoc, LazyNode(node->child1().node()));
+            break;
+        }
+
         case CreateActivation: {
             if (isStillValid(node->castOperand<SymbolTable*>()->singletonScope())) {
                 m_heap.escape(node->child1().node());
@@ -1032,6 +1050,26 @@
                 m_heap.escape(node->child1().node());
             break;
 
+        case GetRegExpObjectLastIndex:
+            target = m_heap.onlyLocalAllocation(node->child1().node());
+            if (target && target->isRegExpObjectAllocation())
+                exactRead = RegExpObjectLastIndexPLoc;
+            else
+                m_heap.escape(node->child1().node());
+            break;
+
+        case SetRegExpObjectLastIndex:
+            target = m_heap.onlyLocalAllocation(node->child1().node());
+            if (target && target->isRegExpObjectAllocation()) {
+                writes.add(
+                    PromotedLocationDescriptor(RegExpObjectLastIndexPLoc),
+                    LazyNode(node->child2().node()));
+            } else {
+                m_heap.escape(node->child1().node());
+                m_heap.escape(node->child2().node());
+            }
+            break;
+
         case Check:
             m_graph.doToChildren(
                 node,
@@ -1508,6 +1546,16 @@
                 OpInfo(symbolTable), OpInfo(data), 0, 0);
         }
 
+        case Allocation::Kind::RegExpObject: {
+            FrozenValue* regExp = allocation.identifier()->cellOperand();
+            return m_graph.addNode(
+                allocation.identifier()->prediction(), NewRegexp,
+                where->origin.withSemantic(
+                    allocation.identifier()->origin.semantic),
+                OpInfo(regExp));
+            break;
+        }
+
         default:
             DFG_CRASH(m_graph, allocation.identifier(), "Bad allocation kind");
         }
@@ -1864,9 +1912,11 @@
                     case NewGeneratorFunction:
                         node->convertToPhantomNewGeneratorFunction();
                         break;
+
                     case NewAsyncGeneratorFunction:
                         node->convertToPhantomNewAsyncGeneratorFunction();
                         break;
+
                     case NewAsyncFunction:
                         node->convertToPhantomNewAsyncFunction();
                         break;
@@ -1875,6 +1925,10 @@
                         node->convertToPhantomCreateActivation();
                         break;
 
+                    case NewRegexp:
+                        node->convertToPhantomNewRegexp();
+                        break;
+
                     default:
                         node->remove();
                         break;
@@ -2143,6 +2197,23 @@
             break;
         }
 
+        case NewRegexp: {
+            Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee);
+            ASSERT(locations.size() == 2);
+
+            PromotedHeapLocation regExp(RegExpObjectRegExpPLoc, allocation.identifier());
+            ASSERT_UNUSED(regExp, locations.contains(regExp));
+
+            PromotedHeapLocation lastIndex(RegExpObjectLastIndexPLoc, allocation.identifier());
+            ASSERT(locations.contains(lastIndex));
+            Node* value = resolve(block, lastIndex);
+            if (m_sinkCandidates.contains(value))
+                node->child1() = Edge(m_bottom);
+            else
+                node->child1() = Edge(value);
+            break;
+        }
+
         default:
             DFG_CRASH(m_graph, node, "Bad materialize op");
         }
@@ -2248,6 +2319,16 @@
             break;
         }
 
+        case RegExpObjectLastIndexPLoc: {
+            return m_graph.addNode(
+                SetRegExpObjectLastIndex,
+                origin.takeValidExit(canExit),
+                OpInfo(true),
+                Edge(base, KnownCellUse),
+                value->defaultEdge());
+            break;
+        }
+
         default:
             DFG_CRASH(m_graph, base, "Bad location kind");
             break;

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -60,6 +60,8 @@
 #include "ObjectConstructor.h"
 #include "Operations.h"
 #include "ParseInt.h"
+#include "RegExpConstructor.h"
+#include "RegExpMatchesArray.h"
 #include "RegExpObject.h"
 #include "Repatch.h"
 #include "ScopedArguments.h"
@@ -1023,6 +1025,32 @@
     return JSValue::encode(asRegExpObject(base)->exec(exec, globalObject, input));
 }
 
+EncodedJSValue JIT_OPERATION operationRegExpExecNonGlobalOrSticky(ExecState* exec, JSGlobalObject* globalObject, RegExp* regExp, JSString* string)
+{
+    SuperSamplerScope superSamplerScope(false);
+
+    VM& vm = globalObject->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    RegExpConstructor* regExpConstructor = globalObject->regExpConstructor();
+    String input = string->value(exec);
+    RETURN_IF_EXCEPTION(scope, { });
+
+    unsigned lastIndex = 0;
+    MatchResult result;
+    JSArray* array = createRegExpMatchesArray(vm, globalObject, string, input, regExp, lastIndex, result);
+    if (!array) {
+        ASSERT(!scope.exception());
+        return JSValue::encode(jsNull());
+    }
+
+    RETURN_IF_EXCEPTION(scope, { });
+    regExpConstructor->recordMatch(vm, regExp, string, result);
+    return JSValue::encode(array);
+}
+
 EncodedJSValue JIT_OPERATION operationRegExpMatchFastString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* argument)
 {
     SuperSamplerScope superSamplerScope(false);
@@ -1876,6 +1904,16 @@
     return jsString(exec, Identifier::from(exec, index).string());
 }
 
+JSCell* JIT_OPERATION operationNewRegexpWithLastIndex(ExecState* exec, JSCell* regexpPtr, EncodedJSValue encodedLastIndex)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    RegExp* regexp = static_cast<RegExp*>(regexpPtr);
+    ASSERT(regexp->isValid());
+    return RegExpObject::create(vm, exec->lexicalGlobalObject()->regExpStructure(), regexp, JSValue::decode(encodedLastIndex));
+}
+
 StringImpl* JIT_OPERATION operationResolveRope(ExecState* exec, JSString* string)
 {
     VM& vm = exec->vm();

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2018-01-18 04:17:32 UTC (rev 227107)
@@ -85,6 +85,7 @@
 JSCell* JIT_OPERATION operationGetPropertyEnumerator(ExecState*, EncodedJSValue);
 JSCell* JIT_OPERATION operationGetPropertyEnumeratorCell(ExecState*, JSCell*);
 JSCell* JIT_OPERATION operationToIndexString(ExecState*, int32_t);
+JSCell* JIT_OPERATION operationNewRegexpWithLastIndex(ExecState*, JSCell*, EncodedJSValue) WTF_INTERNAL;
 char* JIT_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF_INTERNAL;
 char* JIT_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL;
 char* JIT_OPERATION operationNewArrayWithSize(ExecState*, Structure*, int32_t, Butterfly*) WTF_INTERNAL;
@@ -151,6 +152,7 @@
 EncodedJSValue JIT_OPERATION operationRegExpExecString(ExecState*, JSGlobalObject*, RegExpObject*, JSString*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationRegExpExecNonGlobalOrSticky(ExecState*, JSGlobalObject*, RegExp*, JSString*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationRegExpMatchFastString(ExecState*, JSGlobalObject*, RegExpObject*, JSString*) WTF_INTERNAL;
 // These comparisons return a boolean within a size_t such that the value is zero extended to fill the register.
 size_t JIT_OPERATION operationRegExpTestString(ExecState*, JSGlobalObject*, RegExpObject*, JSString*) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -696,6 +696,7 @@
         case ArrayPop:
         case ArrayPush:
         case RegExpExec:
+        case RegExpExecNonGlobalOrSticky:
         case RegExpTest:
         case RegExpMatchFast:
         case StringReplace:
@@ -1091,6 +1092,7 @@
         case PhantomNewArrayWithSpread:
         case PhantomNewArrayBuffer:
         case PhantomClonedArguments:
+        case PhantomNewRegexp:
         case GetMyArgumentByVal:
         case GetMyArgumentByValOutOfBounds:
         case PutHint:

Modified: trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -126,6 +126,14 @@
     case NewArrayBufferPLoc:
         out.print("NewArrayBufferPLoc");
         return;
+
+    case RegExpObjectRegExpPLoc:
+        out.print("RegExpObjectRegExpPLoc");
+        return;
+
+    case RegExpObjectLastIndexPLoc:
+        out.print("RegExpObjectLastIndexPLoc");
+        return;
     }
     
     RELEASE_ASSERT_NOT_REACHED();

Modified: trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.h (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.h	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.h	2018-01-18 04:17:32 UTC (rev 227107)
@@ -64,6 +64,8 @@
     SpreadPLoc,
     NewArrayWithSpreadArgumentPLoc,
     NewArrayBufferPLoc,
+    RegExpObjectRegExpPLoc,
+    RegExpObjectLastIndexPLoc,
 };
 
 class PromotedLocationDescriptor {
@@ -117,6 +119,7 @@
         switch (kind()) {
         case NamedPropertyPLoc:
         case ClosureVarPLoc:
+        case RegExpObjectLastIndexPLoc:
             return false;
 
         default:

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2018-01-18 04:17:32 UTC (rev 227107)
@@ -261,6 +261,7 @@
     case AssertNotEmpty:
     case CheckStringIdent:
     case RegExpExec:
+    case RegExpExecNonGlobalOrSticky:
     case RegExpTest:
     case RegExpMatchFast:
     case CompareLess:
@@ -393,6 +394,7 @@
     case PhantomNewAsyncGeneratorFunction:
     case PhantomNewAsyncFunction:
     case PhantomCreateActivation:
+    case PhantomNewRegexp:
     case PutHint:
     case CheckStructureImmediate:
     case MaterializeNewObject:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -9075,10 +9075,12 @@
     GPRTemporary result(this);
     GPRTemporary scratch1(this);
     GPRTemporary scratch2(this);
+    JSValueOperand lastIndex(this, node->child1());
 
     GPRReg resultGPR = result.gpr();
     GPRReg scratch1GPR = scratch1.gpr();
     GPRReg scratch2GPR = scratch2.gpr();
+    JSValueRegs lastIndexRegs = lastIndex.jsValueRegs();
 
     JITCompiler::JumpList slowPath;
 
@@ -9090,11 +9092,11 @@
     m_jit.storePtr(
         TrustedImmPtr(node->cellOperand()),
         CCallHelpers::Address(resultGPR, RegExpObject::offsetOfRegExp()));
-    m_jit.storeTrustedValue(jsNumber(0), CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndex()));
+    m_jit.storeValue(lastIndexRegs, CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndex()));
     m_jit.store8(TrustedImm32(true), CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndexIsWritable()));
     m_jit.mutatorFence(*m_jit.vm());
 
-    addSlowPathGenerator(slowPathCall(slowPath, this, operationNewRegexp, resultGPR, regexp));
+    addSlowPathGenerator(slowPathCall(slowPath, this, operationNewRegexpWithLastIndex, resultGPR, regexp, lastIndexRegs));
 
     cellResult(resultGPR, node);
 }
@@ -10421,12 +10423,16 @@
     JSValueOperand value(this, node->child2());
     GPRReg regExpGPR = regExp.gpr();
     JSValueRegs valueRegs = value.jsValueRegs();
-    speculateRegExpObject(node->child1(), regExpGPR);
-    speculationCheck(
-        ExoticObjectMode, JSValueRegs(), nullptr,
-        m_jit.branchTest8(
-            JITCompiler::Zero,
-            JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndexIsWritable())));
+
+    if (!node->ignoreLastIndexIsWritable()) {
+        speculateRegExpObject(node->child1(), regExpGPR);
+        speculationCheck(
+            ExoticObjectMode, JSValueRegs(), nullptr,
+            m_jit.branchTest8(
+                JITCompiler::Zero,
+                JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndexIsWritable())));
+    }
+
     m_jit.storeValue(valueRegs, JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndex()));
     noResult(node);
 }
@@ -10620,6 +10626,26 @@
         m_jit.decrementSuperSamplerCount();
 }
 
+void SpeculativeJIT::compileRegExpExecNonGlobalOrSticky(Node* node)
+{
+    SpeculateCellOperand globalObject(this, node->child1());
+    SpeculateCellOperand argument(this, node->child2());
+    GPRReg globalObjectGPR = globalObject.gpr();
+    GPRReg argumentGPR = argument.gpr();
+
+    speculateString(node->child2(), argumentGPR);
+
+    flushRegisters();
+    JSValueRegsFlushedCallResult result(this);
+    JSValueRegs resultRegs = result.regs();
+    callOperation(
+        operationRegExpExecNonGlobalOrSticky, resultRegs,
+        globalObjectGPR, TrustedImmPtr(node->cellOperand()), argumentGPR);
+    m_jit.exceptionCheck();
+
+    jsValueResult(resultRegs, node);
+}
+
 void SpeculativeJIT::compileRegExpMatchFast(Node* node)
 {
     SpeculateCellOperand globalObject(this, node->child1());

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2018-01-18 04:17:32 UTC (rev 227107)
@@ -1431,6 +1431,11 @@
         m_jit.setupArgumentsWithExecState(arg1, arg2.gpr());
         return appendCallSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(C_JITOperation_ECJ operation, GPRReg result, JSCell* arg1, JSValueRegs arg2)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr::weakPointer(m_jit.graph(), arg1), arg2.gpr());
+        return appendCallSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(C_JITOperation_ECO operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2);
@@ -1578,6 +1583,11 @@
         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallSetResult(operation, result.payloadGPR());
     }
+    JITCompiler::Call callOperation(J_JITOperation_EGReJss operation, JSValueRegs result, GPRReg arg1, TrustedImmPtr arg2, GPRReg arg3)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+        return appendCallSetResult(operation, result.payloadGPR());
+    }
     JITCompiler::Call callOperation(C_JITOperation_EJssReo operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2);
@@ -2086,6 +2096,11 @@
         m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR());
         return appendCallSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(C_JITOperation_ECJ operation, GPRReg result, JSCell* arg1, JSValueRegs arg2)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr::weakPointer(m_jit.graph(), arg1), arg2.payloadGPR(), arg2.tagGPR());
+        return appendCallSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(C_JITOperation_ECO operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2);
@@ -2321,6 +2336,11 @@
         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
     }
+    JITCompiler::Call callOperation(J_JITOperation_EGReJss operation, JSValueRegs result, GPRReg arg1, TrustedImmPtr arg2, GPRReg arg3)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+        return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
+    }
     JITCompiler::Call callOperation(J_JITOperation_ESsiCI operation, JSValueRegs result, StructureStubInfo* stubInfo, GPRReg arg1, const UniquedStringImpl* uid)
     {
         m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1, TrustedImmPtr(uid));
@@ -3065,6 +3085,7 @@
     void compileArrayPush(Node*);
     void compileNotifyWrite(Node*);
     void compileRegExpExec(Node*);
+    void compileRegExpExecNonGlobalOrSticky(Node*);
     void compileRegExpMatchFast(Node*);
     void compileRegExpTest(Node*);
     void compileStringReplace(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -3162,6 +3162,11 @@
         compileRegExpExec(node);
         break;
     }
+
+    case RegExpExecNonGlobalOrSticky: {
+        compileRegExpExecNonGlobalOrSticky(node);
+        break;
+    }
         
     case RegExpTest: {
         compileRegExpTest(node);
@@ -5159,6 +5164,7 @@
     case PhantomNewAsyncFunction:
     case PhantomNewAsyncGeneratorFunction:
     case PhantomCreateActivation:
+    case PhantomNewRegexp:
     case PutHint:
     case CheckStructureImmediate:
     case MaterializeCreateActivation:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -3433,6 +3433,11 @@
         break;
     }
 
+    case RegExpExecNonGlobalOrSticky: {
+        compileRegExpExecNonGlobalOrSticky(node);
+        break;
+    }
+
     case RegExpTest: {
         compileRegExpTest(node);
         break;
@@ -5741,6 +5746,7 @@
     case PhantomNewAsyncFunction:
     case PhantomNewAsyncGeneratorFunction:
     case PhantomCreateActivation:
+    case PhantomNewRegexp:
     case GetMyArgumentByVal:
     case GetMyArgumentByValOutOfBounds:
     case GetVectorLength:

Modified: trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -462,7 +462,9 @@
         }
 
         case RegExpExec:
-        case RegExpTest: {
+        case RegExpTest:
+        case RegExpMatchFast:
+        case RegExpExecNonGlobalOrSticky: {
             JSGlobalObject* globalObject = m_node->child1()->dynamicCastConstant<JSGlobalObject*>(vm());
             if (!globalObject) {
                 if (verbose)
@@ -476,250 +478,297 @@
                 break;
             }
 
-            Node* regExpObjectNode = m_node->child2().node();
-            RegExp* regExp;
-            if (RegExpObject* regExpObject = regExpObjectNode->dynamicCastConstant<RegExpObject*>(vm()))
-                regExp = regExpObject->regExp();
-            else if (regExpObjectNode->op() == NewRegexp)
-                regExp = regExpObjectNode->castOperand<RegExp*>();
-            else {
-                if (verbose)
-                    dataLog("Giving up because the regexp is unknown.\n");
-                break;
-            }
+            Node* regExpObjectNode = nullptr;
+            RegExp* regExp = nullptr;
+            if (m_node->op() == RegExpExec || m_node->op() == RegExpTest || m_node->op() == RegExpMatchFast) {
+                regExpObjectNode = m_node->child2().node();
+                if (RegExpObject* regExpObject = regExpObjectNode->dynamicCastConstant<RegExpObject*>(vm()))
+                    regExp = regExpObject->regExp();
+                else if (regExpObjectNode->op() == NewRegexp)
+                    regExp = regExpObjectNode->castOperand<RegExp*>();
+                else {
+                    if (verbose)
+                        dataLog("Giving up because the regexp is unknown.\n");
+                    break;
+                }
+            } else
+                regExp = m_node->castOperand<RegExp*>();
 
-            Node* stringNode = m_node->child3().node();
-            
-            // NOTE: This mostly already protects us from having the compiler execute a regexp
-            // operation on a ginormous string by preventing us from getting our hands on ginormous
-            // strings in the first place.
-            String string = m_node->child3()->tryGetString(m_graph);
-            if (!string) {
-                if (verbose)
-                    dataLog("Giving up because the string is unknown.\n");
-                break;
+            if (m_node->op() == RegExpMatchFast) {
+                if (!regExp->global()) {
+                    m_node->setOp(RegExpExec);
+                    m_changed = true;
+                    // Continue performing strength reduction onto RegExpExec node.
+                } else
+                    break;
             }
 
-            FrozenValue* regExpFrozenValue = m_graph.freeze(regExp);
+            ASSERT(m_node->op() != RegExpMatchFast);
 
-            // Refuse to do things with regular expressions that have a ginormous number of
-            // subpatterns.
-            unsigned ginormousNumberOfSubPatterns = 1000;
-            if (regExp->numSubpatterns() > ginormousNumberOfSubPatterns) {
-                if (verbose)
-                    dataLog("Giving up because of pattern limit.\n");
-                break;
-            }
+            auto foldToConstant = [&] {
+                Node* stringNode = nullptr;
+                if (m_node->op() == RegExpExecNonGlobalOrSticky)
+                    stringNode = m_node->child2().node();
+                else
+                    stringNode = m_node->child3().node();
 
-            if (m_node->op() == RegExpExec && regExp->hasNamedCaptures()) {
-                // FIXME: https://bugs.webkit.org/show_bug.cgi?id=176464
-                // Implement strength reduction optimization for named capture groups.
-                if (verbose)
-                    dataLog("Giving up because of named capture groups.\n");
-                break;
-            }
+                // NOTE: This mostly already protects us from having the compiler execute a regexp
+                // operation on a ginormous string by preventing us from getting our hands on ginormous
+                // strings in the first place.
+                String string = stringNode->tryGetString(m_graph);
+                if (!string) {
+                    if (verbose)
+                        dataLog("Giving up because the string is unknown.\n");
+                    return false;
+                }
 
-            unsigned lastIndex;
-            if (regExp->globalOrSticky()) {
-                // This will only work if we can prove what the value of lastIndex is. To do this
-                // safely, we need to execute the insertion set so that we see any previous strength
-                // reductions. This is needed for soundness since otherwise the effectfulness of any
-                // previous strength reductions would be invisible to us.
-                executeInsertionSet();
-                lastIndex = UINT_MAX;
-                for (unsigned otherNodeIndex = m_nodeIndex; otherNodeIndex--;) {
-                    Node* otherNode = m_block->at(otherNodeIndex);
-                    if (otherNode == regExpObjectNode) {
-                        lastIndex = 0;
-                        break;
-                    }
-                    if (otherNode->op() == SetRegExpObjectLastIndex
-                        && otherNode->child1() == regExpObjectNode
-                        && otherNode->child2()->isInt32Constant()
-                        && otherNode->child2()->asInt32() >= 0) {
-                        lastIndex = static_cast<unsigned>(otherNode->child2()->asInt32());
-                        break;
-                    }
-                    if (writesOverlap(m_graph, otherNode, RegExpObject_lastIndex))
-                        break;
+                FrozenValue* regExpFrozenValue = m_graph.freeze(regExp);
+
+                // Refuse to do things with regular expressions that have a ginormous number of
+                // subpatterns.
+                unsigned ginormousNumberOfSubPatterns = 1000;
+                if (regExp->numSubpatterns() > ginormousNumberOfSubPatterns) {
+                    if (verbose)
+                        dataLog("Giving up because of pattern limit.\n");
+                    return false;
                 }
-                if (lastIndex == UINT_MAX) {
+
+                if ((m_node->op() == RegExpExec || m_node->op() == RegExpExecNonGlobalOrSticky) && regExp->hasNamedCaptures()) {
+                    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=176464
+                    // Implement strength reduction optimization for named capture groups.
                     if (verbose)
-                        dataLog("Giving up because the last index is not known.\n");
-                    break;
+                        dataLog("Giving up because of named capture groups.\n");
+                    return false;
                 }
-            } else
-                lastIndex = 0;
 
-            m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
-            
-            Structure* structure;
-            if (m_node->op() == RegExpExec && regExp->hasNamedCaptures())
-                structure = globalObject->regExpMatchesArrayWithGroupsStructure();
-            else
-                structure = globalObject->regExpMatchesArrayStructure();
+                unsigned lastIndex;
+                if (regExp->globalOrSticky()) {
+                    // This will only work if we can prove what the value of lastIndex is. To do this
+                    // safely, we need to execute the insertion set so that we see any previous strength
+                    // reductions. This is needed for soundness since otherwise the effectfulness of any
+                    // previous strength reductions would be invisible to us.
+                    ASSERT(regExpObjectNode);
+                    executeInsertionSet();
+                    lastIndex = UINT_MAX;
+                    for (unsigned otherNodeIndex = m_nodeIndex; otherNodeIndex--;) {
+                        Node* otherNode = m_block->at(otherNodeIndex);
+                        if (otherNode == regExpObjectNode) {
+                            lastIndex = 0;
+                            break;
+                        }
+                        if (otherNode->op() == SetRegExpObjectLastIndex
+                            && otherNode->child1() == regExpObjectNode
+                            && otherNode->child2()->isInt32Constant()
+                            && otherNode->child2()->asInt32() >= 0) {
+                            lastIndex = static_cast<unsigned>(otherNode->child2()->asInt32());
+                            break;
+                        }
+                        if (writesOverlap(m_graph, otherNode, RegExpObject_lastIndex))
+                            break;
+                    }
+                    if (lastIndex == UINT_MAX) {
+                        if (verbose)
+                            dataLog("Giving up because the last index is not known.\n");
+                        return false;
+                    }
+                } else
+                    lastIndex = 0;
 
-            if (structure->indexingType() != ArrayWithContiguous) {
-                // This is further protection against a race with haveABadTime.
-                if (verbose)
-                    dataLog("Giving up because the structure has the wrong indexing type.\n");
-                break;
-            }
-            m_graph.registerStructure(structure);
+                m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
 
-            RegExpConstructor* constructor = globalObject->regExpConstructor();
-            FrozenValue* constructorFrozenValue = m_graph.freeze(constructor);
+                Structure* structure;
+                if ((m_node->op() == RegExpExec || m_node->op() == RegExpExecNonGlobalOrSticky) && regExp->hasNamedCaptures())
+                    structure = globalObject->regExpMatchesArrayWithGroupsStructure();
+                else
+                    structure = globalObject->regExpMatchesArrayStructure();
 
-            MatchResult result;
-            Vector<int> ovector;
-            // We have to call the kind of match function that the main thread would have called.
-            // Otherwise, we might not have the desired Yarr code compiled, and the match will fail.
-            if (m_node->op() == RegExpExec) {
-                int position;
-                if (!regExp->matchConcurrently(vm(), string, lastIndex, position, ovector)) {
+                if (structure->indexingType() != ArrayWithContiguous) {
+                    // This is further protection against a race with haveABadTime.
                     if (verbose)
-                        dataLog("Giving up because match failed.\n");
-                    break;
+                        dataLog("Giving up because the structure has the wrong indexing type.\n");
+                    return false;
                 }
-                result.start = position;
-                result.end = ovector[1];
-            } else {
-                if (!regExp->matchConcurrently(vm(), string, lastIndex, result)) {
-                    if (verbose)
-                        dataLog("Giving up because match failed.\n");
-                    break;
+                m_graph.registerStructure(structure);
+
+                RegExpConstructor* constructor = globalObject->regExpConstructor();
+                FrozenValue* constructorFrozenValue = m_graph.freeze(constructor);
+
+                MatchResult result;
+                Vector<int> ovector;
+                // We have to call the kind of match function that the main thread would have called.
+                // Otherwise, we might not have the desired Yarr code compiled, and the match will fail.
+                if (m_node->op() == RegExpExec || m_node->op() == RegExpExecNonGlobalOrSticky) {
+                    int position;
+                    if (!regExp->matchConcurrently(vm(), string, lastIndex, position, ovector)) {
+                        if (verbose)
+                            dataLog("Giving up because match failed.\n");
+                        return false;
+                    }
+                    result.start = position;
+                    result.end = ovector[1];
+                } else {
+                    if (!regExp->matchConcurrently(vm(), string, lastIndex, result)) {
+                        if (verbose)
+                            dataLog("Giving up because match failed.\n");
+                        return false;
+                    }
                 }
-            }
 
-            // We've constant-folded the regexp. Now we're committed to replacing RegExpExec/Test.
+                // We've constant-folded the regexp. Now we're committed to replacing RegExpExec/Test.
 
-            m_changed = true;
+                m_changed = true;
 
-            NodeOrigin origin = m_node->origin;
+                NodeOrigin origin = m_node->origin;
 
-            m_insertionSet.insertNode(
-                m_nodeIndex, SpecNone, Check, origin, m_node->children.justChecks());
+                m_insertionSet.insertNode(
+                    m_nodeIndex, SpecNone, Check, origin, m_node->children.justChecks());
 
-            if (m_node->op() == RegExpExec) {
-                if (result) {
-                    RegisteredStructureSet* structureSet = m_graph.addStructureSet(structure);
+                if (m_node->op() == RegExpExec || m_node->op() == RegExpExecNonGlobalOrSticky) {
+                    if (result) {
+                        RegisteredStructureSet* structureSet = m_graph.addStructureSet(structure);
 
-                    // Create an array modeling the JS array that we will try to allocate. This is
-                    // basically createRegExpMatchesArray but over C++ strings instead of JSStrings.
-                    Vector<String> resultArray;
-                    resultArray.append(string.substring(result.start, result.end - result.start));
-                    for (unsigned i = 1; i <= regExp->numSubpatterns(); ++i) {
-                        int start = ovector[2 * i];
-                        if (start >= 0)
-                            resultArray.append(string.substring(start, ovector[2 * i + 1] - start));
-                        else
-                            resultArray.append(String());
-                    }
+                        // Create an array modeling the JS array that we will try to allocate. This is
+                        // basically createRegExpMatchesArray but over C++ strings instead of JSStrings.
+                        Vector<String> resultArray;
+                        resultArray.append(string.substring(result.start, result.end - result.start));
+                        for (unsigned i = 1; i <= regExp->numSubpatterns(); ++i) {
+                            int start = ovector[2 * i];
+                            if (start >= 0)
+                                resultArray.append(string.substring(start, ovector[2 * i + 1] - start));
+                            else
+                                resultArray.append(String());
+                        }
 
-                    unsigned publicLength = resultArray.size();
-                    unsigned vectorLength =
-                        Butterfly::optimalContiguousVectorLength(structure, publicLength);
+                        unsigned publicLength = resultArray.size();
+                        unsigned vectorLength =
+                            Butterfly::optimalContiguousVectorLength(structure, publicLength);
 
-                    UniquedStringImpl* indexUID = vm().propertyNames->index.impl();
-                    UniquedStringImpl* inputUID = vm().propertyNames->input.impl();
-                    unsigned indexIndex = m_graph.identifiers().ensure(indexUID);
-                    unsigned inputIndex = m_graph.identifiers().ensure(inputUID);
+                        UniquedStringImpl* indexUID = vm().propertyNames->index.impl();
+                        UniquedStringImpl* inputUID = vm().propertyNames->input.impl();
+                        unsigned indexIndex = m_graph.identifiers().ensure(indexUID);
+                        unsigned inputIndex = m_graph.identifiers().ensure(inputUID);
 
+                        unsigned firstChild = m_graph.m_varArgChildren.size();
+                        m_graph.m_varArgChildren.append(
+                            m_insertionSet.insertConstantForUse(
+                                m_nodeIndex, origin, structure, KnownCellUse));
+                        ObjectMaterializationData* data = ""
+
+                        m_graph.m_varArgChildren.append(
+                            m_insertionSet.insertConstantForUse(
+                                m_nodeIndex, origin, jsNumber(publicLength), KnownInt32Use));
+                        data->m_properties.append(PublicLengthPLoc);
+
+                        m_graph.m_varArgChildren.append(
+                            m_insertionSet.insertConstantForUse(
+                                m_nodeIndex, origin, jsNumber(vectorLength), KnownInt32Use));
+                        data->m_properties.append(VectorLengthPLoc);
+
+                        m_graph.m_varArgChildren.append(
+                            m_insertionSet.insertConstantForUse(
+                                m_nodeIndex, origin, jsNumber(result.start), UntypedUse));
+                        data->m_properties.append(
+                            PromotedLocationDescriptor(NamedPropertyPLoc, indexIndex));
+
+                        m_graph.m_varArgChildren.append(Edge(stringNode, UntypedUse));
+                        data->m_properties.append(
+                            PromotedLocationDescriptor(NamedPropertyPLoc, inputIndex));
+
+                        auto materializeString = [&] (const String& string) -> Node* {
+                            if (string.isNull())
+                                return nullptr;
+                            if (string.isEmpty()) {
+                                return m_insertionSet.insertConstant(
+                                    m_nodeIndex, origin, vm().smallStrings.emptyString());
+                            }
+                            LazyJSValue value = LazyJSValue::newString(m_graph, string);
+                            return m_insertionSet.insertNode(
+                                m_nodeIndex, SpecNone, LazyJSConstant, origin,
+                                OpInfo(m_graph.m_lazyJSValues.add(value)));
+                        };
+
+                        for (unsigned i = 0; i < resultArray.size(); ++i) {
+                            if (Node* node = materializeString(resultArray[i])) {
+                                m_graph.m_varArgChildren.append(Edge(node, UntypedUse));
+                                data->m_properties.append(
+                                    PromotedLocationDescriptor(IndexedPropertyPLoc, i));
+                            }
+                        }
+
+                        Node* resultNode = m_insertionSet.insertNode(
+                            m_nodeIndex, SpecArray, Node::VarArg, MaterializeNewObject, origin,
+                            OpInfo(structureSet), OpInfo(data), firstChild,
+                            m_graph.m_varArgChildren.size() - firstChild);
+
+                        m_node->convertToIdentityOn(resultNode);
+                    } else
+                        m_graph.convertToConstant(m_node, jsNull());
+                } else
+                    m_graph.convertToConstant(m_node, jsBoolean(!!result));
+
+                // Whether it's Exec or Test, we need to tell the constructor and RegExpObject what's up.
+                // Because SetRegExpObjectLastIndex may exit and it clobbers exit state, we do that
+                // first.
+
+                if (regExp->globalOrSticky()) {
+                    ASSERT(regExpObjectNode);
+                    m_insertionSet.insertNode(
+                        m_nodeIndex, SpecNone, SetRegExpObjectLastIndex, origin,
+                        OpInfo(false),
+                        Edge(regExpObjectNode, RegExpObjectUse),
+                        m_insertionSet.insertConstantForUse(
+                            m_nodeIndex, origin, jsNumber(result ? result.end : 0), UntypedUse));
+
+                    origin = origin.withInvalidExit();
+                }
+
+                if (result) {
                     unsigned firstChild = m_graph.m_varArgChildren.size();
                     m_graph.m_varArgChildren.append(
                         m_insertionSet.insertConstantForUse(
-                            m_nodeIndex, origin, structure, KnownCellUse));
-                    ObjectMaterializationData* data = ""
-            
+                            m_nodeIndex, origin, constructorFrozenValue, KnownCellUse));
                     m_graph.m_varArgChildren.append(
                         m_insertionSet.insertConstantForUse(
-                            m_nodeIndex, origin, jsNumber(publicLength), KnownInt32Use));
-                    data->m_properties.append(PublicLengthPLoc);
-            
+                            m_nodeIndex, origin, regExpFrozenValue, KnownCellUse));
+                    m_graph.m_varArgChildren.append(Edge(stringNode, KnownCellUse));
                     m_graph.m_varArgChildren.append(
                         m_insertionSet.insertConstantForUse(
-                            m_nodeIndex, origin, jsNumber(vectorLength), KnownInt32Use));
-                    data->m_properties.append(VectorLengthPLoc);
-
+                            m_nodeIndex, origin, jsNumber(result.start), KnownInt32Use));
                     m_graph.m_varArgChildren.append(
                         m_insertionSet.insertConstantForUse(
-                            m_nodeIndex, origin, jsNumber(result.start), UntypedUse));
-                    data->m_properties.append(
-                        PromotedLocationDescriptor(NamedPropertyPLoc, indexIndex));
+                            m_nodeIndex, origin, jsNumber(result.end), KnownInt32Use));
+                    m_insertionSet.insertNode(
+                        m_nodeIndex, SpecNone, Node::VarArg, RecordRegExpCachedResult, origin,
+                        OpInfo(), OpInfo(), firstChild, m_graph.m_varArgChildren.size() - firstChild);
 
-                    m_graph.m_varArgChildren.append(Edge(stringNode, UntypedUse));
-                    data->m_properties.append(
-                        PromotedLocationDescriptor(NamedPropertyPLoc, inputIndex));
+                    origin = origin.withInvalidExit();
+                }
 
-                    auto materializeString = [&] (const String& string) -> Node* {
-                        if (string.isNull())
-                            return nullptr;
-                        if (string.isEmpty()) {
-                            return m_insertionSet.insertConstant(
-                                m_nodeIndex, origin, vm().smallStrings.emptyString());
-                        }
-                        LazyJSValue value = LazyJSValue::newString(m_graph, string);
-                        return m_insertionSet.insertNode(
-                            m_nodeIndex, SpecNone, LazyJSConstant, origin,
-                            OpInfo(m_graph.m_lazyJSValues.add(value)));
-                    };
+                m_node->origin = origin;
+                return true;
+            };
 
-                    for (unsigned i = 0; i < resultArray.size(); ++i) {
-                        if (Node* node = materializeString(resultArray[i])) {
-                            m_graph.m_varArgChildren.append(Edge(node, UntypedUse));
-                            data->m_properties.append(
-                                PromotedLocationDescriptor(IndexedPropertyPLoc, i));
-                        }
-                    }
-            
-                    Node* resultNode = m_insertionSet.insertNode(
-                        m_nodeIndex, SpecArray, Node::VarArg, MaterializeNewObject, origin,
-                        OpInfo(structureSet), OpInfo(data), firstChild,
-                        m_graph.m_varArgChildren.size() - firstChild);
-                
-                    m_node->convertToIdentityOn(resultNode);
-                } else
-                    m_graph.convertToConstant(m_node, jsNull());
-            } else
-                m_graph.convertToConstant(m_node, jsBoolean(!!result));
-
-            // Whether it's Exec or Test, we need to tell the constructor and RegExpObject what's up.
-            // Because SetRegExpObjectLastIndex may exit and it clobbers exit state, we do that
-            // first.
-            
-            if (regExp->globalOrSticky()) {
+            auto convertToStatic = [&] {
+                if (m_node->op() != RegExpExec)
+                    return false;
+                if (regExp->globalOrSticky())
+                    return false;
+                if (m_node->child3().useKind() != StringUse)
+                    return false;
+                NodeOrigin origin = m_node->origin;
                 m_insertionSet.insertNode(
-                    m_nodeIndex, SpecNone, SetRegExpObjectLastIndex, origin,
-                    Edge(regExpObjectNode, RegExpObjectUse),
-                    m_insertionSet.insertConstantForUse(
-                        m_nodeIndex, origin, jsNumber(result ? result.end : 0), UntypedUse));
-                
-                origin = origin.withInvalidExit();
-            }
+                    m_nodeIndex, SpecNone, Check, origin, m_node->children.justChecks());
+                m_node->convertToRegExpExecNonGlobalOrSticky(m_graph.freeze(regExp));
+                m_changed = true;
+                return true;
+            };
 
-            if (result) {
-                unsigned firstChild = m_graph.m_varArgChildren.size();
-                m_graph.m_varArgChildren.append(
-                    m_insertionSet.insertConstantForUse(
-                        m_nodeIndex, origin, constructorFrozenValue, KnownCellUse));
-                m_graph.m_varArgChildren.append(
-                    m_insertionSet.insertConstantForUse(
-                        m_nodeIndex, origin, regExpFrozenValue, KnownCellUse));
-                m_graph.m_varArgChildren.append(Edge(stringNode, KnownCellUse));
-                m_graph.m_varArgChildren.append(
-                    m_insertionSet.insertConstantForUse(
-                        m_nodeIndex, origin, jsNumber(result.start), KnownInt32Use));
-                m_graph.m_varArgChildren.append(
-                    m_insertionSet.insertConstantForUse(
-                        m_nodeIndex, origin, jsNumber(result.end), KnownInt32Use));
-                m_insertionSet.insertNode(
-                    m_nodeIndex, SpecNone, Node::VarArg, RecordRegExpCachedResult, origin,
-                    OpInfo(), OpInfo(), firstChild, m_graph.m_varArgChildren.size() - firstChild);
+            if (foldToConstant())
+                break;
 
-                origin = origin.withInvalidExit();
-            }
-            
-            m_node->origin = origin;
+            if (convertToStatic())
+                break;
+
             break;
         }
 
@@ -802,6 +851,7 @@
             if (regExp->global()) {
                 m_insertionSet.insertNode(
                     m_nodeIndex, SpecNone, SetRegExpObjectLastIndex, origin,
+                    OpInfo(false),
                     Edge(regExpObjectNode, RegExpObjectUse),
                     m_insertionSet.insertConstantForUse(
                         m_nodeIndex, origin, jsNumber(0), UntypedUse));

Modified: trunk/Source/_javascript_Core/dfg/DFGValidate.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -582,6 +582,7 @@
                 case PhantomNewAsyncFunction:
                 case PhantomNewAsyncGeneratorFunction:
                 case PhantomCreateActivation:
+                case PhantomNewRegexp:
                 case GetMyArgumentByVal:
                 case GetMyArgumentByValOutOfBounds:
                 case PutHint:
@@ -738,6 +739,7 @@
                 case PhantomDirectArguments:
                 case PhantomCreateRest:
                 case PhantomClonedArguments:
+                case PhantomNewRegexp:
                 case MovHint:
                 case Upsilon:
                 case ForwardVarargs:

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -246,6 +246,7 @@
     case PhantomNewAsyncGeneratorFunction:
     case PhantomNewAsyncFunction:
     case PhantomCreateActivation:
+    case PhantomNewRegexp:
     case PutHint:
     case CheckStructureImmediate:
     case MaterializeNewObject:
@@ -276,6 +277,7 @@
     case CreateRest:
     case GetRestLength:
     case RegExpExec:
+    case RegExpExecNonGlobalOrSticky:
     case RegExpTest:
     case RegExpMatchFast:
     case NewRegexp:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -1182,6 +1182,9 @@
         case RegExpExec:
             compileRegExpExec();
             break;
+        case RegExpExecNonGlobalOrSticky:
+            compileRegExpExecNonGlobalOrSticky();
+            break;
         case RegExpTest:
             compileRegExpTest();
             break;
@@ -1267,6 +1270,7 @@
         case PhantomNewArrayWithSpread:
         case PhantomNewArrayBuffer:
         case PhantomClonedArguments:
+        case PhantomNewRegexp:
         case PutHint:
         case BottomValue:
         case KillStack:
@@ -10260,6 +10264,15 @@
         setJSValue(result);
     }
 
+    void compileRegExpExecNonGlobalOrSticky()
+    {
+        LValue globalObject = lowCell(m_node->child1());
+        LValue argument = lowString(m_node->child2());
+        LValue result = vmCall(
+            Int64, m_out.operation(operationRegExpExecNonGlobalOrSticky), m_callFrame, globalObject, frozenPointer(m_node->cellOperand()), argument);
+        setJSValue(result);
+    }
+
     void compileRegExpTest()
     {
         LValue globalObject = lowCell(m_node->child1());
@@ -10306,6 +10319,7 @@
     void compileNewRegexp()
     {
         FrozenValue* regexp = m_node->cellOperand();
+        LValue lastIndex = lowJSValue(m_node->child1());
         ASSERT(regexp->cell()->inherits(vm(), RegExp::info()));
         ASSERT(m_node->castOperand<RegExp*>()->isValid());
 
@@ -10317,7 +10331,7 @@
         auto structure = m_graph.registerStructure(m_graph.globalObjectFor(m_node->origin.semantic)->regExpStructure());
         LValue fastResultValue = allocateObject<RegExpObject>(structure, m_out.intPtrZero, m_out.int32Zero, slowCase);
         m_out.storePtr(frozenPointer(regexp), fastResultValue, m_heaps.RegExpObject_regExp);
-        m_out.store64(m_out.constInt64(JSValue::encode(jsNumber(0))), fastResultValue, m_heaps.RegExpObject_lastIndex);
+        m_out.store64(lastIndex, fastResultValue, m_heaps.RegExpObject_lastIndex);
         m_out.store32As8(m_out.constInt32(true), m_out.address(fastResultValue, m_heaps.RegExpObject_lastIndexIsWritable));
         mutatorFence();
         ValueFromBlock fastResult = m_out.anchor(fastResultValue);
@@ -10329,9 +10343,9 @@
         LValue slowResultValue = lazySlowPath(
             [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> {
                 return createLazyCallGenerator(vm,
-                    operationNewRegexp, locations[0].directGPR(),
-                    CCallHelpers::TrustedImmPtr(regexpCell));
-            });
+                    operationNewRegexpWithLastIndex, locations[0].directGPR(),
+                    CCallHelpers::TrustedImmPtr(regexpCell), locations[1].directGPR());
+            }, lastIndex);
         ValueFromBlock slowResult = m_out.anchor(slowResultValue);
         m_out.jump(continuation);
 
@@ -10398,14 +10412,19 @@
 
     void compileSetRegExpObjectLastIndex()
     {
-        LValue regExp = lowRegExpObject(m_node->child1());
-        LValue value = lowJSValue(m_node->child2());
+        if (!m_node->ignoreLastIndexIsWritable()) {
+            LValue regExp = lowRegExpObject(m_node->child1());
+            LValue value = lowJSValue(m_node->child2());
 
-        speculate(
-            ExoticObjectMode, noValue(), nullptr,
-            m_out.isZero32(m_out.load8ZeroExt32(regExp, m_heaps.RegExpObject_lastIndexIsWritable)));
+            speculate(
+                ExoticObjectMode, noValue(), nullptr,
+                m_out.isZero32(m_out.load8ZeroExt32(regExp, m_heaps.RegExpObject_lastIndexIsWritable)));
+
+            m_out.store64(value, regExp, m_heaps.RegExpObject_lastIndex);
+            return;
+        }
         
-        m_out.store64(value, regExp, m_heaps.RegExpObject_lastIndex);
+        m_out.store64(lowJSValue(m_node->child2()), lowCell(m_node->child1()), m_heaps.RegExpObject_lastIndex);
     }
     
     void compileLogShadowChickenPrologue()

Modified: trunk/Source/_javascript_Core/ftl/FTLOperations.cpp (227106 => 227107)


--- trunk/Source/_javascript_Core/ftl/FTLOperations.cpp	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/ftl/FTLOperations.cpp	2018-01-18 04:17:32 UTC (rev 227107)
@@ -40,6 +40,7 @@
 #include "JSFixedArray.h"
 #include "JSGeneratorFunction.h"
 #include "JSLexicalEnvironment.h"
+#include "RegExpObject.h"
 
 namespace JSC { namespace FTL {
 
@@ -110,7 +111,20 @@
         break;
     }
 
+    case PhantomNewRegexp: {
+        RegExpObject* regExpObject = jsCast<RegExpObject*>(JSValue::decode(*encodedValue));
 
+        for (unsigned i = materialization->properties().size(); i--;) {
+            const ExitPropertyValue& property = materialization->properties()[i];
+            if (property.location().kind() != RegExpObjectLastIndexPLoc)
+                continue;
+
+            regExpObject->setLastIndex(exec, JSValue::decode(values[i]), false /* shouldThrow */);
+            break;
+        }
+        break;
+    }
+
     default:
         RELEASE_ASSERT_NOT_REACHED();
         break;
@@ -533,7 +547,21 @@
         return result;
     }
 
-        
+    case PhantomNewRegexp: {
+        RegExp* regExp = nullptr;
+        for (unsigned i = materialization->properties().size(); i--;) {
+            const ExitPropertyValue& property = materialization->properties()[i];
+            if (property.location() == PromotedLocationDescriptor(RegExpObjectRegExpPLoc)) {
+                RELEASE_ASSERT(JSValue::decode(values[i]).asCell()->inherits(vm, RegExp::info()));
+                regExp = jsCast<RegExp*>(JSValue::decode(values[i]));
+            }
+        }
+        RELEASE_ASSERT(regExp);
+        CodeBlock* codeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock(materialization->origin(), exec->codeBlock());
+        Structure* structure = codeBlock->globalObject()->regExpStructure();
+        return RegExpObject::create(vm, structure, regExp);
+    }
+
     default:
         RELEASE_ASSERT_NOT_REACHED();
         return nullptr;

Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (227106 => 227107)


--- trunk/Source/_javascript_Core/jit/JITOperations.h	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h	2018-01-18 04:17:32 UTC (rev 227107)
@@ -51,6 +51,7 @@
 class JSScope;
 class JSString;
 class JSValue;
+class RegExp;
 class RegExpObject;
 class Register;
 class Structure;
@@ -103,6 +104,7 @@
     Pc: Instruction* i.e. bytecode PC
     Q: int64_t
     R: Register
+    Re: RegExp*
     Reo: RegExpObject*
     S: size_t
     Sprt: SlowPathReturnType
@@ -136,6 +138,7 @@
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGReoJ)(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGReoJss)(ExecState*, JSGlobalObject*, RegExpObject*, JSString*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGJJ)(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue);
+typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGReJss)(ExecState*, JSGlobalObject*, RegExp*, JSString*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EI)(ExecState*, UniquedStringImpl*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJ)(ExecState*, EncodedJSValue);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJZ)(ExecState*, EncodedJSValue, int32_t);

Modified: trunk/Source/_javascript_Core/runtime/RegExpObject.h (227106 => 227107)


--- trunk/Source/_javascript_Core/runtime/RegExpObject.h	2018-01-18 03:15:26 UTC (rev 227106)
+++ trunk/Source/_javascript_Core/runtime/RegExpObject.h	2018-01-18 04:17:32 UTC (rev 227107)
@@ -39,6 +39,13 @@
         return object;
     }
 
+    static RegExpObject* create(VM& vm, Structure* structure, RegExp* regExp, JSValue lastIndex)
+    {
+        auto* object = create(vm, structure, regExp);
+        object->m_lastIndex.set(vm, object, lastIndex);
+        return object;
+    }
+
     void setRegExp(VM& vm, RegExp* r) { m_regExp.set(vm, this, r); }
     RegExp* regExp() const { return m_regExp.get(); }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to