Title: [200272] trunk
Revision
200272
Author
mark....@apple.com
Date
2016-04-29 17:34:01 -0700 (Fri, 29 Apr 2016)

Log Message

Make RegExp.prototype.test spec compliant.
https://bugs.webkit.org/show_bug.cgi?id=155862

Reviewed by Saam Barati.

Source/_javascript_Core:

* builtins/RegExpPrototype.js:
(intrinsic.RegExpTestIntrinsic.test):

* create_hash_table:
- Delete obsoleted code.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addToGraph):
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
- We now have 2 intrinsics for RegExp.prototype.test:
  RegExpTestIntrinsic and RegExpTestFastIntrinsic.

  RegExpTestIntrinsic maps to the entry at the top of the builtin ES6
  RegExp.prototype.test.
  RegExpTestFastIntrinsic maps to the fast path in the builtin ES6
  RegExp.prototype.test.

  Both will end up using the RegExpTest DFG node to implement the fast path
  of RegExp.prototype.test.  RegExpTestIntrinsic will have some additional checks
  before the RegExpTest node.  Those checks are for speculating that it is ok for
  us to take the fast path.

* runtime/CommonIdentifiers.h:
* runtime/Intrinsic.h:

* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
- Added the regExpTestFast function.
- Also fixed the parameter length on 2 other functions that were erroneous.

* runtime/RegExpPrototype.cpp:
(JSC::RegExpPrototype::finishCreation):
(JSC::regExpProtoFuncTestFast):
(JSC::regExpProtoFuncTest): Deleted.
* runtime/RegExpPrototype.h:
* tests/es6.yaml:

LayoutTests:

* js/regress/regexp-prototype-test-observable-side-effects-expected.txt: Added.
* js/regress/regexp-prototype-test-observable-side-effects.html: Added.
* js/regress/regexp-prototype-test-observable-side-effects2-expected.txt: Added.
* js/regress/regexp-prototype-test-observable-side-effects2.html: Added.
* js/regress/script-tests/regexp-prototype-test-observable-side-effects.js: Added.
* js/regress/script-tests/simple-regexp-test-folding-fail-with-hoisted-regexp.js: Added.
* js/regress/script-tests/simple-regexp-test-folding-with-hoisted-regexp.js: Added.
* js/regress/simple-regexp-test-folding-fail-with-hoisted-regexp-expected.txt: Added.
* js/regress/simple-regexp-test-folding-fail-with-hoisted-regexp.html: Added.
* js/regress/simple-regexp-test-folding-with-hoisted-regexp-expected.txt: Added.
* js/regress/simple-regexp-test-folding-with-hoisted-regexp.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (200271 => 200272)


--- trunk/LayoutTests/ChangeLog	2016-04-30 00:12:35 UTC (rev 200271)
+++ trunk/LayoutTests/ChangeLog	2016-04-30 00:34:01 UTC (rev 200272)
@@ -1,3 +1,22 @@
+2016-04-29  Mark Lam  <mark....@apple.com>
+
+        Make RegExp.prototype.test spec compliant.
+        https://bugs.webkit.org/show_bug.cgi?id=155862
+
+        Reviewed by Saam Barati.
+
+        * js/regress/regexp-prototype-test-observable-side-effects-expected.txt: Added.
+        * js/regress/regexp-prototype-test-observable-side-effects.html: Added.
+        * js/regress/regexp-prototype-test-observable-side-effects2-expected.txt: Added.
+        * js/regress/regexp-prototype-test-observable-side-effects2.html: Added.
+        * js/regress/script-tests/regexp-prototype-test-observable-side-effects.js: Added.
+        * js/regress/script-tests/simple-regexp-test-folding-fail-with-hoisted-regexp.js: Added.
+        * js/regress/script-tests/simple-regexp-test-folding-with-hoisted-regexp.js: Added.
+        * js/regress/simple-regexp-test-folding-fail-with-hoisted-regexp-expected.txt: Added.
+        * js/regress/simple-regexp-test-folding-fail-with-hoisted-regexp.html: Added.
+        * js/regress/simple-regexp-test-folding-with-hoisted-regexp-expected.txt: Added.
+        * js/regress/simple-regexp-test-folding-with-hoisted-regexp.html: Added.
+
 2016-04-29  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, rolling out r200150 and r200256.

Added: trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects-expected.txt (0 => 200272)


--- trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects-expected.txt	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,10 @@
+JSRegress/regexp-prototype-test-observable-side-effects
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects.html (0 => 200272)


--- trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects.html	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
+

Added: trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects2-expected.txt (0 => 200272)


--- trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects2-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects2-expected.txt	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,10 @@
+JSRegress/regexp-prototype-test-observable-side-effects2
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects2.html (0 => 200272)


--- trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects2.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/regexp-prototype-test-observable-side-effects2.html	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
+

Added: trunk/LayoutTests/js/regress/script-tests/regexp-prototype-test-observable-side-effects.js (0 => 200272)


--- trunk/LayoutTests/js/regress/script-tests/regexp-prototype-test-observable-side-effects.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/regexp-prototype-test-observable-side-effects.js	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,277 @@
+//@ runDefault
+
+function assert(testedValue, msg) {
+    if (!testedValue)
+        throw Error(msg);
+}
+
+// RegExp subclass overriding exec.
+(function () {
+    let accesses = [];
+    class SubRegExp extends RegExp {
+        exec(str) {
+            accesses.push("exec");
+            return super.exec(str);
+        }
+    }
+
+    let obj = new SubRegExp(/rch/);
+
+    assert(accesses == "", "unexpected call to overridden props");
+    let result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === true, "Unexpected result");
+
+    accesses = [];
+    obj = new SubRegExp(/not/);
+
+    assert(accesses == "", "unexpected call to overridden props");
+    result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === false, "Unexpected result");
+})();
+ 
+// Any object with custom prototype overriding exec.
+(function () {
+    let accesses = [];
+    let TestRegExpProto = {
+        exec(str) {
+            accesses.push("exec");
+            return this._regex.exec(str);
+        }
+    }
+    TestRegExpProto.__proto__ = RegExp.prototype;
+
+    let TestRegExp = function(regex) {
+        this._regex = new RegExp(regex);
+    }
+    TestRegExp.prototype = TestRegExpProto;
+    TestRegExpProto.constructor = TestRegExp;
+
+    let obj = new TestRegExp(/rch/);
+
+    assert(accesses == "", "unexpected call to overridden props");
+    let result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === true, "Unexpected result");
+
+    accesses = [];
+    obj = new TestRegExp(/not/);
+
+    assert(accesses == "", "unexpected call to overridden props");
+    result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === false, "Unexpected result");
+})();
+
+// 2 levels of RegExp subclasses with the middle parent overriding exec.
+(function () {
+    let accesses = [];
+    class RegExpB extends RegExp {
+        exec(str) {
+            accesses.push("exec");
+            return super.exec(str);
+        }
+    }
+    class RegExpC extends RegExpB { }
+
+    assert(RegExpB.__proto__ == RegExp);
+    assert(RegExpC.__proto__ == RegExpB);
+
+    let obj = new RegExpC(/rch/);
+
+    assert(accesses == "", "unexpected call to overridden props");
+    let result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === true, "Unexpected result");
+
+    accesses = [];
+    obj = new RegExpC(/not/);
+
+    assert(accesses == "", "unexpected call to overridden props");
+    result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === false, "Unexpected result");
+})();
+
+// 2 levels of RegExp subclasses with substituted prototype before instantiation.
+(function () {
+    let accesses = [];
+    let regExpForOverriddenExec = /rch/;
+
+    class B extends RegExp { }
+    class C extends B { }
+
+    assert(B.__proto__ === RegExp);
+    assert(C.__proto__ === B);
+    assert(B.prototype.__proto__ === RegExp.prototype);
+    assert(C.prototype.__proto__ === B.prototype);
+
+    let X = function () {}
+    Object.defineProperty(X.prototype, "exec", {
+        value: function(str) {
+            accesses.push("exec");
+            return regExpForOverriddenExec.exec(str);
+        }
+    });
+
+    // Monkey with the prototype chain before instantiating C.
+    X.__proto__ = RegExp;
+    X.prototype.__proto__ = RegExp.prototype;
+    C.__proto__ = X;
+    C.prototype.__proto__ = X.prototype;
+
+    assert(X.__proto__ === RegExp);
+    assert(C.__proto__ === X);
+    assert(X.prototype.__proto__ === RegExp.prototype);
+    assert(C.prototype.__proto__ === X.prototype);
+
+    let obj = new C();
+
+    assert(accesses == "", "unexpected call to overridden props");
+    let result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === true, "Unexpected result");
+
+    accesses = [];
+    regExpForOverriddenExec = /not/;
+
+    assert(accesses == "", "unexpected call to overridden props");
+    result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === false, "Unexpected result");
+})();
+
+// 2 levels of RegExp subclasses with substituted prototype after instantiation.
+(function () {
+    let accesses = [];
+    let regExpForOverriddenExec = /rch/;
+
+    class B extends RegExp { }
+    class C extends B { }
+
+    assert(B.__proto__ === RegExp);
+    assert(C.__proto__ === B);
+    assert(B.prototype.__proto__ === RegExp.prototype);
+    assert(C.prototype.__proto__ === B.prototype);
+
+    let obj = new C();
+
+    let X = function () {}
+    Object.defineProperty(X.prototype, "exec", {
+        value: function(str) {
+            accesses.push("exec");
+            return regExpForOverriddenExec.exec(str);
+        }
+    });
+
+    // Monkey with the prototype chain after instantiating C.
+    X.__proto__ = RegExp;
+    X.prototype.__proto__ = RegExp.prototype;
+    C.__proto__ = X;
+    C.prototype.__proto__ = X.prototype;
+
+    assert(X.__proto__ === RegExp);
+    assert(C.__proto__ === X);
+    assert(X.prototype.__proto__ === RegExp.prototype);
+    assert(C.prototype.__proto__ === X.prototype);
+
+    assert(accesses == "", "unexpected call to overridden props");
+    let result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === true, "Unexpected result");
+
+    accesses = [];
+    regExpForOverriddenExec = /not/;
+
+    assert(accesses == "", "unexpected call to overridden props");
+    result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === false, "Unexpected result");
+})();
+
+// 2 levels of RegExp subclasses with proxied prototype.
+(function () {
+    let accesses = [];
+    let regExpForOverriddenExec = /rch/;
+
+    class B extends RegExp { };
+
+    assert(B.__proto__ === RegExp);
+    assert(B.prototype.__proto__ === RegExp.prototype);
+
+    let proxy = new Proxy(RegExp.prototype, {
+        get: function(obj, prop) {
+            accesses.push("get_" + prop.toString());
+
+            function proxyExec(str) {
+                accesses.push("exec");
+                return regExpForOverriddenExec.exec(str);
+            }
+
+            if (prop === "exec")
+                return proxyExec;
+            return obj[prop];
+        },
+        set: function(obj, prop, value) {
+            accesses.push("set_" + prop.toString());
+        }
+    });
+    B.prototype.__proto__ = proxy;
+
+    let obj = new B();
+
+    assert(accesses == "", "unexpected call to overridden props");
+    let result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "get_exec,exec", "Property accesses do not match expectation");
+    assert(result === true, "Unexpected result");
+
+    accesses = [];
+    regExpForOverriddenExec = /not/;
+
+    assert(accesses == "", "unexpected call to overridden props");
+    result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "get_exec,exec", "Property accesses do not match expectation");
+    assert(result === false, "Unexpected result");
+})();
+
+// Proxied RegExp observing every get.
+(function () {
+    let accesses = [];
+    let regexp = new RegExp(/rch/);
+    let proxy = new Proxy(regexp, {
+        get(obj, prop) {
+            accesses.push(prop.toString());
+            if (prop == "exec") {
+                return function(str) {
+                    return obj.exec(str);
+                }
+            }
+            return obj[prop];
+        }
+    });
+
+    assert(accesses == "", "unexpected call to overridden props");
+    let result = RegExp.prototype.test.call(proxy, "searchme");
+    assert(accesses.toString() == "exec", "Proxy not able to observe some gets");
+    assert(result === true, "Unexpected result");
+
+    accesses = [];
+    regexp = new RegExp(/not/);
+    proxy = new Proxy(regexp, {
+        get(obj, prop) {
+            accesses.push(prop.toString());
+            if (prop == "exec") {
+                return function(str) {
+                    return obj.exec(str);
+                }
+            }
+            return obj[prop];
+        }
+    });
+
+    assert(accesses == "", "unexpected call to overridden props");
+    result = RegExp.prototype.test.call(proxy, "searchme");
+    assert(accesses.toString() == "exec", "Proxy not able to observe some gets");
+    assert(result === false, "Unexpected result");
+})();

Added: trunk/LayoutTests/js/regress/script-tests/regexp-prototype-test-observable-side-effects2.js (0 => 200272)


--- trunk/LayoutTests/js/regress/script-tests/regexp-prototype-test-observable-side-effects2.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/regexp-prototype-test-observable-side-effects2.js	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,34 @@
+//@ runDefault
+
+function assert(testedValue, msg) {
+    if (!testedValue)
+        throw Error(msg);
+}
+
+// RegExp.prototype with overridden exec.
+(function () {
+    let accesses = [];
+    let origExec = RegExp.prototype.exec;
+
+    let obj = /rch/;
+    Object.defineProperty(RegExp.prototype, "exec", {
+        value: function(str) {
+            accesses.push("exec");
+            return origExec.call(this, str);
+        }
+    });
+
+    assert(accesses == "", "unexpected call to overridden props");
+    let result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === true, "Unexpected result");
+
+    accesses = [];
+    obj = /not/;
+
+    assert(accesses == "", "unexpected call to overridden props");
+    result = RegExp.prototype.test.call(obj, "searchme");
+    assert(accesses == "exec", "Property accesses do not match expectation");
+    assert(result === false, "Unexpected result");
+})();
+

Added: trunk/LayoutTests/js/regress/script-tests/simple-regexp-test-folding-fail-with-hoisted-regexp.js (0 => 200272)


--- trunk/LayoutTests/js/regress/script-tests/simple-regexp-test-folding-fail-with-hoisted-regexp.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/simple-regexp-test-folding-fail-with-hoisted-regexp.js	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,9 @@
+(function() {
+    for (var j = 0; j < 10; ++j) {
+        (function () {
+            var regExp = /foo/;
+            for (var i = 0; i < 100000; ++i)
+                regExp.test("bar");
+        })();
+    }
+})();

Added: trunk/LayoutTests/js/regress/script-tests/simple-regexp-test-folding-with-hoisted-regexp.js (0 => 200272)


--- trunk/LayoutTests/js/regress/script-tests/simple-regexp-test-folding-with-hoisted-regexp.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/simple-regexp-test-folding-with-hoisted-regexp.js	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,9 @@
+(function() {
+    for (var j = 0; j < 10; ++j) {
+        (function () {
+            var regExp = /foo/;
+            for (var i = 0; i < 100000; ++i)
+                regExp.test("foo");
+        })();
+    }
+})();

Added: trunk/LayoutTests/js/regress/simple-regexp-test-folding-fail-with-hoisted-regexp-expected.txt (0 => 200272)


--- trunk/LayoutTests/js/regress/simple-regexp-test-folding-fail-with-hoisted-regexp-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/simple-regexp-test-folding-fail-with-hoisted-regexp-expected.txt	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,10 @@
+JSRegress/simple-regexp-test-folding-fail-with-hoisted-regexp
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/simple-regexp-test-folding-fail-with-hoisted-regexp.html (0 => 200272)


--- trunk/LayoutTests/js/regress/simple-regexp-test-folding-fail-with-hoisted-regexp.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/simple-regexp-test-folding-fail-with-hoisted-regexp.html	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/simple-regexp-test-folding-with-hoisted-regexp-expected.txt (0 => 200272)


--- trunk/LayoutTests/js/regress/simple-regexp-test-folding-with-hoisted-regexp-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/simple-regexp-test-folding-with-hoisted-regexp-expected.txt	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,10 @@
+JSRegress/simple-regexp-test-folding-with-hoisted-regexp
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/simple-regexp-test-folding-with-hoisted-regexp.html (0 => 200272)


--- trunk/LayoutTests/js/regress/simple-regexp-test-folding-with-hoisted-regexp.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/simple-regexp-test-folding-with-hoisted-regexp.html	2016-04-30 00:34:01 UTC (rev 200272)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Modified: trunk/Source/_javascript_Core/ChangeLog (200271 => 200272)


--- trunk/Source/_javascript_Core/ChangeLog	2016-04-30 00:12:35 UTC (rev 200271)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-04-30 00:34:01 UTC (rev 200272)
@@ -1,3 +1,47 @@
+2016-04-29  Mark Lam  <mark....@apple.com>
+
+        Make RegExp.prototype.test spec compliant.
+        https://bugs.webkit.org/show_bug.cgi?id=155862
+
+        Reviewed by Saam Barati.
+
+        * builtins/RegExpPrototype.js:
+        (intrinsic.RegExpTestIntrinsic.test):
+
+        * create_hash_table:
+        - Delete obsoleted code.
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::addToGraph):
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        - We now have 2 intrinsics for RegExp.prototype.test:
+          RegExpTestIntrinsic and RegExpTestFastIntrinsic.
+
+          RegExpTestIntrinsic maps to the entry at the top of the builtin ES6
+          RegExp.prototype.test.
+          RegExpTestFastIntrinsic maps to the fast path in the builtin ES6
+          RegExp.prototype.test.
+
+          Both will end up using the RegExpTest DFG node to implement the fast path
+          of RegExp.prototype.test.  RegExpTestIntrinsic will have some additional checks
+          before the RegExpTest node.  Those checks are for speculating that it is ok for
+          us to take the fast path.
+
+        * runtime/CommonIdentifiers.h:
+        * runtime/Intrinsic.h:
+
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        - Added the regExpTestFast function.
+        - Also fixed the parameter length on 2 other functions that were erroneous.
+
+        * runtime/RegExpPrototype.cpp:
+        (JSC::RegExpPrototype::finishCreation):
+        (JSC::regExpProtoFuncTestFast):
+        (JSC::regExpProtoFuncTest): Deleted.
+        * runtime/RegExpPrototype.h:
+        * tests/es6.yaml:
+
 2016-04-29  Benjamin Poulain  <benja...@webkit.org>
 
         Extend math-pow-stable-results.js to get more information about the failure

Modified: trunk/Source/_javascript_Core/builtins/RegExpPrototype.js (200271 => 200272)


--- trunk/Source/_javascript_Core/builtins/RegExpPrototype.js	2016-04-30 00:12:35 UTC (rev 200271)
+++ trunk/Source/_javascript_Core/builtins/RegExpPrototype.js	2016-04-30 00:34:01 UTC (rev 200272)
@@ -487,3 +487,31 @@
     // 22. Return A.
     return result;
 }
+
+// ES 21.2.5.13 RegExp.prototype.test(string)
+[intrinsic=RegExpTestIntrinsic] function test(strArg)
+{
+    "use strict";
+
+    let regexp = this;
+
+    // Check for observable side effects and call the fast path if there aren't any.
+    if (@isRegExpObject(regexp) && @tryGetById(regexp, "exec") === @regExpBuiltinExec)
+        return @regExpTestFast.@call(regexp, strArg);
+
+    // 1. Let R be the this value.
+    // 2. If Type(R) is not Object, throw a TypeError exception.
+    if (!@isObject(regexp))
+        throw new @TypeError("RegExp.prototype.test requires that |this| be an Object");
+
+    // 3. Let string be ? ToString(S).
+    let str = @toString(strArg);
+
+    // 4. Let match be ? RegExpExec(R, string).
+    let match = @regExpExec(regexp, str);
+
+    // 5. If match is not null, return true; else return false.
+    if (match !== null)
+        return true;
+    return false;
+}

Modified: trunk/Source/_javascript_Core/create_hash_table (200271 => 200272)


--- trunk/Source/_javascript_Core/create_hash_table	2016-04-30 00:12:35 UTC (rev 200271)
+++ trunk/Source/_javascript_Core/create_hash_table	2016-04-30 00:34:01 UTC (rev 200272)
@@ -306,10 +306,6 @@
             $intrinsic = "ArrayPushIntrinsic" if ($key eq "push");
             $intrinsic = "ArrayPopIntrinsic" if ($key eq "pop");
         }
-        if ($name eq "regExpPrototypeTable") {
-            $intrinsic = "RegExpExecIntrinsic" if ($key eq "exec");
-            $intrinsic = "RegExpTestIntrinsic" if ($key eq "test");
-        }
 
         if ($values[$i]{"type"} eq "Function" && $firstValue eq "JSBuiltin")  {
             my $tableHead = $name;

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (200271 => 200272)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-04-30 00:12:35 UTC (rev 200271)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-04-30 00:34:01 UTC (rev 200272)
@@ -48,7 +48,7 @@
 #include "PreciseJumpTargets.h"
 #include "PutByIdFlags.h"
 #include "PutByIdStatus.h"
-#include <RegExpPrototype.h>
+#include "RegExpPrototype.h"
 #include "StackAlignment.h"
 #include "StringConstructor.h"
 #include "StructureStubInfo.h"
@@ -721,6 +721,11 @@
             Edge(child3));
         return addToGraph(result);
     }
+    Node* addToGraph(NodeType op, OpInfo info, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
+    {
+        Node* result = m_graph.addNode(SpecNone, op, currentNodeOrigin(), info, child1, child2, child3);
+        return addToGraph(result);
+    }
     Node* addToGraph(NodeType op, OpInfo info1, OpInfo info2, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
     {
         Node* result = m_graph.addNode(
@@ -728,6 +733,12 @@
             Edge(child1), Edge(child2), Edge(child3));
         return addToGraph(result);
     }
+    Node* addToGraph(NodeType op, OpInfo info1, OpInfo info2, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
+    {
+        Node* result = m_graph.addNode(
+            SpecNone, op, currentNodeOrigin(), info1, info2, child1, child2, child3);
+        return addToGraph(result);
+    }
     
     Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2)
     {
@@ -2205,12 +2216,52 @@
         return true;
     }
         
-    case RegExpTestIntrinsic: {
+    case RegExpTestIntrinsic:
+    case RegExpTestFastIntrinsic: {
         if (argumentCountIncludingThis != 2)
             return false;
-        
+
+        if (intrinsic == RegExpTestIntrinsic) {
+            // Don't inline intrinsic if we exited due to one of the primordial RegExp checks failing.
+            if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell))
+                return false;
+
+            JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
+            Structure* regExpStructure = globalObject->regExpStructure();
+            m_graph.registerStructure(regExpStructure);
+            ASSERT(regExpStructure->storedPrototype().isObject());
+            ASSERT(regExpStructure->storedPrototype().asCell()->classInfo() == RegExpPrototype::info());
+
+            FrozenValue* regExpPrototypeObjectValue = m_graph.freeze(regExpStructure->storedPrototype());
+            Structure* regExpPrototypeStructure = regExpPrototypeObjectValue->structure();
+
+            auto isRegExpPropertySame = [&] (JSValue primordialProperty, UniquedStringImpl* propertyUID) {
+                JSValue currentProperty;
+                if (!m_graph.getRegExpPrototypeProperty(regExpStructure->storedPrototypeObject(), regExpPrototypeStructure, propertyUID, currentProperty))
+                    return false;
+                
+                return currentProperty == primordialProperty;
+            };
+
+            // Check that RegExp.exec is still the primordial RegExp.prototype.exec
+            if (!isRegExpPropertySame(globalObject->regExpProtoExecFunction(), m_vm->propertyNames->exec.impl()))
+                return false;
+
+            // Check that regExpObject is actually a RegExp object.
+            Node* regExpObject = get(virtualRegisterForArgument(0, registerOffset));
+            addToGraph(Check, Edge(regExpObject, RegExpObjectUse));
+
+            // Check that regExpObject's exec is actually the primodial RegExp.prototype.exec.
+            UniquedStringImpl* execPropertyID = m_vm->propertyNames->exec.impl();
+            unsigned execIndex = m_graph.identifiers().ensure(execPropertyID);
+            Node* actualProperty = addToGraph(TryGetById, OpInfo(execIndex), OpInfo(SpecFunction), Edge(regExpObject, CellUse));
+            FrozenValue* regExpPrototypeExec = m_graph.freeze(globalObject->regExpProtoExecFunction());
+            addToGraph(CheckCell, OpInfo(regExpPrototypeExec), Edge(actualProperty, CellUse));
+        }
+
         insertChecks();
-        Node* regExpExec = addToGraph(RegExpTest, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)));
+        Node* regExpObject = get(virtualRegisterForArgument(0, registerOffset));
+        Node* regExpExec = addToGraph(RegExpTest, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), regExpObject, get(virtualRegisterForArgument(1, registerOffset)));
         set(VirtualRegister(resultOperand), regExpExec);
         
         return true;

Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (200271 => 200272)


--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2016-04-30 00:12:35 UTC (rev 200271)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2016-04-30 00:34:01 UTC (rev 200272)
@@ -436,10 +436,11 @@
     macro(regExpProtoSourceGetter) \
     macro(regExpProtoStickyGetter) \
     macro(regExpProtoUnicodeGetter) \
+    macro(regExpPrototypeSymbolReplace) \
     macro(regExpReplaceFast) \
     macro(regExpSearchFast) \
     macro(regExpSplitFast) \
-    macro(regExpPrototypeSymbolReplace) \
+    macro(regExpTestFast) \
     macro(stringIncludesInternal) \
     macro(stringSplitFast) \
     macro(stringSubstrInternal) \

Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (200271 => 200272)


--- trunk/Source/_javascript_Core/runtime/Intrinsic.h	2016-04-30 00:12:35 UTC (rev 200271)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h	2016-04-30 00:34:01 UTC (rev 200272)
@@ -51,6 +51,7 @@
     LogIntrinsic,
     RegExpExecIntrinsic,
     RegExpTestIntrinsic,
+    RegExpTestFastIntrinsic,
     StringPrototypeValueOfIntrinsic,
     StringPrototypeReplaceIntrinsic,
     StringPrototypeReplaceRegExpIntrinsic,

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (200271 => 200272)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2016-04-30 00:12:35 UTC (rev 200271)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2016-04-30 00:34:01 UTC (rev 200272)
@@ -652,10 +652,11 @@
         GlobalPropertyInfo(vm.propertyNames->builtinNames().hasObservableSideEffectsForRegExpSplitPrivateName(), JSFunction::createBuiltinFunction(vm, regExpPrototypeHasObservableSideEffectsForRegExpSplitCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().advanceStringIndexPrivateName(), JSFunction::createBuiltinFunction(vm, regExpPrototypeAdvanceStringIndexCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().regExpExecPrivateName(), JSFunction::createBuiltinFunction(vm, regExpPrototypeRegExpExecCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
-        GlobalPropertyInfo(vm.propertyNames->regExpMatchFastPrivateName, JSFunction::create(vm, this, 2, String(), regExpProtoFuncMatchFast), DontEnum | DontDelete | ReadOnly),
-        GlobalPropertyInfo(vm.propertyNames->regExpSearchFastPrivateName, JSFunction::create(vm, this, 2, String(), regExpProtoFuncSearchFast), DontEnum | DontDelete | ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->regExpMatchFastPrivateName, JSFunction::create(vm, this, 1, String(), regExpProtoFuncMatchFast), DontEnum | DontDelete | ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->regExpSearchFastPrivateName, JSFunction::create(vm, this, 1, String(), regExpProtoFuncSearchFast), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->regExpSplitFastPrivateName, JSFunction::create(vm, this, 2, String(), regExpProtoFuncSplitFast), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->regExpPrototypeSymbolReplacePrivateName, m_regExpPrototype->getDirect(vm, vm.propertyNames->replaceSymbol), DontEnum | DontDelete | ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->regExpTestFastPrivateName, JSFunction::create(vm, this, 1, String(), regExpProtoFuncTestFast, RegExpTestFastIntrinsic), DontEnum | DontDelete | ReadOnly),
 
         // String.prototype helpers.
         GlobalPropertyInfo(vm.propertyNames->builtinNames().hasObservableSideEffectsForStringReplacePrivateName(), JSFunction::createBuiltinFunction(vm, stringPrototypeHasObservableSideEffectsForStringReplaceCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),

Modified: trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp (200271 => 200272)


--- trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp	2016-04-30 00:12:35 UTC (rev 200271)
+++ trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp	2016-04-30 00:34:01 UTC (rev 200272)
@@ -44,7 +44,6 @@
 
 namespace JSC {
 
-static EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState*);
 static EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*);
 static EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*);
 static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*);
@@ -69,7 +68,6 @@
     ASSERT(inherits(info()));
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->compile, regExpProtoFuncCompile, DontEnum, 2);
     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->exec, regExpProtoFuncExec, DontEnum, 1, RegExpExecIntrinsic);
-    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->test, regExpProtoFuncTest, DontEnum, 1, RegExpTestIntrinsic);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, regExpProtoFuncToString, DontEnum, 0);
     JSC_NATIVE_GETTER(vm.propertyNames->global, regExpProtoGetterGlobal, DontEnum | Accessor);
     JSC_NATIVE_GETTER(vm.propertyNames->ignoreCase, regExpProtoGetterIgnoreCase, DontEnum | Accessor);
@@ -82,6 +80,7 @@
     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->replaceSymbol, regExpPrototypeReplaceCodeGenerator, DontEnum);
     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->searchSymbol, regExpPrototypeSearchCodeGenerator, DontEnum);
     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->splitSymbol, regExpPrototypeSplitCodeGenerator, DontEnum);
+    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->test, regExpPrototypeTestCodeGenerator, DontEnum);
 
     m_emptyRegExp.set(vm, this, RegExp::create(vm, "", NoFlags));
 }
@@ -97,7 +96,7 @@
 
 // ------------------------------ Functions ---------------------------
 
-EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL regExpProtoFuncTestFast(ExecState* exec)
 {
     JSValue thisValue = exec->thisValue();
     if (!thisValue.inherits(RegExpObject::info()))

Modified: trunk/Source/_javascript_Core/runtime/RegExpPrototype.h (200271 => 200272)


--- trunk/Source/_javascript_Core/runtime/RegExpPrototype.h	2016-04-30 00:12:35 UTC (rev 200271)
+++ trunk/Source/_javascript_Core/runtime/RegExpPrototype.h	2016-04-30 00:34:01 UTC (rev 200272)
@@ -61,6 +61,7 @@
 EncodedJSValue JSC_HOST_CALL regExpProtoFuncMatchFast(ExecState*);
 EncodedJSValue JSC_HOST_CALL regExpProtoFuncSearchFast(ExecState*);
 EncodedJSValue JSC_HOST_CALL regExpProtoFuncSplitFast(ExecState*);
+EncodedJSValue JSC_HOST_CALL regExpProtoFuncTestFast(ExecState*);
 
 } // namespace JSC
 

Modified: trunk/Source/_javascript_Core/tests/es6.yaml (200271 => 200272)


--- trunk/Source/_javascript_Core/tests/es6.yaml	2016-04-30 00:12:35 UTC (rev 200271)
+++ trunk/Source/_javascript_Core/tests/es6.yaml	2016-04-30 00:34:01 UTC (rev 200272)
@@ -997,7 +997,7 @@
 - path: es6/Proxy_internal_get_calls_RegExp.prototype.flags.js
   cmd: runES6 :normal
 - path: es6/Proxy_internal_get_calls_RegExp.prototype.test.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Proxy_internal_get_calls_RegExp.prototype.toString.js
   cmd: runES6 :normal
 - path: es6/Proxy_internal_get_calls_RegExp.prototype[Symbol.match].js
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to