We don't model regexp effects properly
https://bugs.webkit.org/show_bug.cgi?id=185059
<rdar://problem/39736150>

Reviewed by Filip Pizlo.

JSTests:

* stress/regexp-exec-test-effectful-last-index.js: Added.
(assert):
(foo):
(i.regexLastIndex.toString):
(bar):

Source/JavaScriptCore:

RegExp exec/test can do arbitrary effects when toNumbering the lastIndex if
the regexp is global.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@231145 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index d4fb07a..9fe2b28 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,3 +1,17 @@
+2018-04-28  Saam Barati  <sbarati@apple.com>
+
+        We don't model regexp effects properly
+        https://bugs.webkit.org/show_bug.cgi?id=185059
+        <rdar://problem/39736150>
+
+        Reviewed by Filip Pizlo.
+
+        * stress/regexp-exec-test-effectful-last-index.js: Added.
+        (assert):
+        (foo):
+        (i.regexLastIndex.toString):
+        (bar):
+
 2018-04-28  Rick Waldron  <waldron.rick@gmail.com>
 
         Token misspelled "tocken" in error message string
diff --git a/JSTests/stress/regexp-exec-test-effectful-last-index.js b/JSTests/stress/regexp-exec-test-effectful-last-index.js
new file mode 100644
index 0000000..ef68e55
--- /dev/null
+++ b/JSTests/stress/regexp-exec-test-effectful-last-index.js
@@ -0,0 +1,50 @@
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+
+let outer = 42;
+
+function foo(r, s) {
+    let y = outer;
+    r.test(s);
+    return y + outer;
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; ++i) {
+    let r = /foo/g;
+    regexLastIndex = {};
+    regexLastIndex.toString = function() {
+        outer = 1;
+        return "1";
+    };
+
+    r.lastIndex = regexLastIndex;
+    let result = foo(r, "bar");
+    assert(result === 43);
+
+    outer = 42;
+}
+
+function bar(r, s) {
+    let y = outer;
+    r.exec(s);
+    return y + outer;
+}
+noInline(bar);
+
+for (let i = 0; i < 10000; ++i) {
+    let r = /foo/g;
+    regexLastIndex = {};
+    regexLastIndex.toString = function() {
+        outer = 1;
+        return "1";
+    };
+
+    r.lastIndex = regexLastIndex;
+    let result = bar(r, "bar");
+    assert(result === 43);
+
+    outer = 42;
+}
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 40f58c7..e736a31 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,19 @@
+2018-04-28  Saam Barati  <sbarati@apple.com>
+
+        We don't model regexp effects properly
+        https://bugs.webkit.org/show_bug.cgi?id=185059
+        <rdar://problem/39736150>
+
+        Reviewed by Filip Pizlo.
+
+        RegExp exec/test can do arbitrary effects when toNumbering the lastIndex if
+        the regexp is global.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+
 2018-04-28  Rick Waldron  <waldron.rick@gmail.com>
 
         Token misspelled "tocken" in error message string
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 6f85734..c3afd0c 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -2010,11 +2010,9 @@
     case RegExpExec:
     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);
+            // Even if we've proven known input types as RegExpObject and String,
+            // accessing lastIndex is effectful if it's a global regexp.
+            clobberWorld(node->origin.semantic, clobberLimit);
         }
 
         if (JSValue globalObjectValue = forNode(node->child1()).m_value) {
@@ -2034,11 +2032,9 @@
         break;
 
     case RegExpTest:
-        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);
+        // Even if we've proven known input types as RegExpObject and String,
+        // accessing lastIndex is effectful if it's a global regexp.
+        clobberWorld(node->origin.semantic, clobberLimit);
         forNode(node).setType(SpecBoolean);
         break;
 
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index 24fd941..dd68a59 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -1513,19 +1513,19 @@
 
     case RegExpExec:
     case RegExpTest:
-    case RegExpMatchFast:
-        if (node->child2().useKind() == RegExpObjectUse
-            && node->child3().useKind() == StringUse) {
-            read(RegExpState);
-            read(RegExpObject_lastIndex);
-            write(RegExpState);
-            write(RegExpObject_lastIndex);
-            return;
-        }
+        // Even if we've proven known input types as RegExpObject and String,
+        // accessing lastIndex is effectful if it's a global regexp.
         read(World);
         write(Heap);
         return;
 
+    case RegExpMatchFast:
+        read(RegExpState);
+        read(RegExpObject_lastIndex);
+        write(RegExpState);
+        write(RegExpObject_lastIndex);
+        return;
+
     case RegExpExecNonGlobalOrSticky:
     case RegExpMatchFastGlobal:
         read(RegExpState);