Cherry-pick "Refactor Regexp.prototype"

Original change: https://chromium-review.googlesource.com/c/v8/v8/+/1547660
Adds unit test.

Bug: 147664838
Test: m -j proxy_resolver_v8_unittest && adb sync && adb shell \
      /data/nativetest/proxy_resolver_v8_unittest/proxy_resolver_v8_unittest
Merged-In: I6b8f8f2eff548cab5bbc69f7ba981381043227da
Change-Id: I6b8f8f2eff548cab5bbc69f7ba981381043227da
(cherry picked from commit 780b5e342028c8c7964145483ac73eca941ed464)
diff --git a/test/js-unittest/b_147664838.js b/test/js-unittest/b_147664838.js
new file mode 100644
index 0000000..d1d8b72
--- /dev/null
+++ b/test/js-unittest/b_147664838.js
@@ -0,0 +1,21 @@
+function FindProxyForURL(url, host){
+  let re = /x/y;
+  let cnt = 0;
+  let str = re[Symbol.replace]("x", {
+    toString: () => {
+      cnt++;
+      if (cnt == 2) {
+        re.lastIndex = {valueOf: () => {
+          re.x = 42;
+          return 0;
+        }};
+      }
+      return 'y$';
+    }
+  });
+  if (str != "y$") {
+    throw "regex mutated";
+    return "FAIL";
+  }
+  return "DIRECT";
+}
\ No newline at end of file
diff --git a/test/proxy_resolver_v8_unittest.cc b/test/proxy_resolver_v8_unittest.cc
index fa11f73..e66f68b 100644
--- a/test/proxy_resolver_v8_unittest.cc
+++ b/test/proxy_resolver_v8_unittest.cc
@@ -586,6 +586,19 @@
   EXPECT_EQ("DIRECT", proxies[0]);
 }
 
+TEST(ProxyResolverV8Test, B_147664838) {
+  ProxyResolverV8WithMockBindings resolver(new MockJSBindings());
+  int result = resolver.SetPacScript(SCRIPT(B_147664838_JS));
+  EXPECT_EQ(OK, result);
+
+  // Execute FindProxyForURL().
+  result = resolver.GetProxyForURL(kQueryUrl, kQueryHost, &kResults);
+
+  EXPECT_EQ(OK, result);
+  std::vector<std::string> proxies = string16ToProxyList(kResults);
+  EXPECT_EQ(1U, proxies.size());
+  EXPECT_EQ("DIRECT", proxies[0]);
+}
 
 }  // namespace
 }  // namespace net
diff --git a/test/proxy_test_script.h b/test/proxy_test_script.h
index bb8502c..0deb19f 100644
--- a/test/proxy_test_script.h
+++ b/test/proxy_test_script.h
@@ -33,6 +33,30 @@
   "    return \"DIRECT\";\n" \
   "}\n" \
 
+#define B_147664838_JS \
+  u""\
+  "function FindProxyForURL(url, host){\n" \
+  "  let re = /x/y;\n" \
+  "  let cnt = 0;\n" \
+  "  let str = re[Symbol.replace](\"x\", {\n" \
+  "    toString: () => {\n" \
+  "      cnt++;\n" \
+  "      if (cnt == 2) {\n" \
+  "        re.lastIndex = {valueOf: () => {\n" \
+  "          re.x = 42;\n" \
+  "          return 0;\n" \
+  "        }};\n" \
+  "      }\n" \
+  "      return 'y$';\n" \
+  "    }\n" \
+  "  });\n" \
+  "  if (str != \"y$\") {\n" \
+  "    throw \"regex mutated\";\n" \
+  "    return \"FAIL\";\n" \
+  "  }\n" \
+  "  return \"DIRECT\";\n" \
+  "}\n" \
+
 #define BINDING_FROM_GLOBAL_JS \
   "// Calls a bindings outside of FindProxyForURL(). This causes the code to\n" \
   "// get exercised during initialization.\n" \