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