https://bugs.webkit.org/show_bug.cgi?id=154266
Reviewed by Saam Barati.
Adds FTL support for NewRegexp, RegExpTest, and RegExpExec. I couldn't figure out how to
make the RegExpExec peephole optimization work in FTL. This optimizations shouldn't be a
DFG backend optimization anyway - if we need this optimization then it should be a
strength reduction rule over IR. That way, it can be shared by all backends.
I measured whether removing that optimization had any effect on performance separately
from measuring the performance of this patch. Removing that optimization did not change
our score on any benchmarks.
This patch does have an overall negative effect on the Octane/regexp score. This is
presumably because tiering up to the FTL has no value to the code in the regexp test. Or
maybe it's something else. No matter - the overall effect on the Octane score is not
statistically significant and we don't want this kind of coverage blocked by the fact
that adding coverage hurts a benchmark.
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGNode.h:
(JSC::DFG::Node::setIndexingType):
(JSC::DFG::Node::hasRegexpIndex):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileNotifyWrite):
(JSC::DFG::SpeculativeJIT::compileIsObjectOrNull):
(JSC::DFG::SpeculativeJIT::compileRegExpExec): Deleted.
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileCheckWatchdogTimer):
(JSC::FTL::DFG::LowerDFGToB3::compileRegExpExec):
(JSC::FTL::DFG::LowerDFGToB3::compileRegExpTest):
(JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
(JSC::FTL::DFG::LowerDFGToB3::didOverflowStack):
* tests/stress/ftl-regexp-exec.js: Added.
* tests/stress/ftl-regexp-test.js: Added.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@197357
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2016-02-28 Filip Pizlo <fpizlo@apple.com>
+
+ FTL should be able to run everything in Octane/regexp
+ https://bugs.webkit.org/show_bug.cgi?id=154266
+
+ Reviewed by Saam Barati.
+
+ Adds FTL support for NewRegexp, RegExpTest, and RegExpExec. I couldn't figure out how to
+ make the RegExpExec peephole optimization work in FTL. This optimizations shouldn't be a
+ DFG backend optimization anyway - if we need this optimization then it should be a
+ strength reduction rule over IR. That way, it can be shared by all backends.
+
+ I measured whether removing that optimization had any effect on performance separately
+ from measuring the performance of this patch. Removing that optimization did not change
+ our score on any benchmarks.
+
+ This patch does have an overall negative effect on the Octane/regexp score. This is
+ presumably because tiering up to the FTL has no value to the code in the regexp test. Or
+ maybe it's something else. No matter - the overall effect on the Octane score is not
+ statistically significant and we don't want this kind of coverage blocked by the fact
+ that adding coverage hurts a benchmark.
+
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::setIndexingType):
+ (JSC::DFG::Node::hasRegexpIndex):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileNotifyWrite):
+ (JSC::DFG::SpeculativeJIT::compileIsObjectOrNull):
+ (JSC::DFG::SpeculativeJIT::compileRegExpExec): Deleted.
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::compileCheckWatchdogTimer):
+ (JSC::FTL::DFG::LowerDFGToB3::compileRegExpExec):
+ (JSC::FTL::DFG::LowerDFGToB3::compileRegExpTest):
+ (JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
+ (JSC::FTL::DFG::LowerDFGToB3::didOverflowStack):
+ * tests/stress/ftl-regexp-exec.js: Added.
+ * tests/stress/ftl-regexp-test.js: Added.
+
2016-02-28 Andreas Kling <akling@apple.com>
Make JSFunction.name allocation fully lazy.
}
case op_new_regexp: {
+ // FIXME: We really should be able to inline code that uses NewRegexp. That means
+ // using something other than the index into the CodeBlock here.
+ // https://bugs.webkit.org/show_bug.cgi?id=154808
set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewRegexp, OpInfo(currentInstruction[2].u.operand)));
NEXT_OPCODE(op_new_regexp);
}
m_opInfo = indexingType;
}
+ // FIXME: We really should be able to inline code that uses NewRegexp. That means
+ // using something other than the index into the CodeBlock here.
+ // https://bugs.webkit.org/show_bug.cgi?id=154808
bool hasRegexpIndex()
{
return op() == NewRegexp;
noResult(node);
}
-bool SpeculativeJIT::compileRegExpExec(Node* node)
-{
- unsigned branchIndexInBlock = detectPeepHoleBranch();
- if (branchIndexInBlock == UINT_MAX)
- return false;
- Node* branchNode = m_block->at(branchIndexInBlock);
- ASSERT(node->adjustedRefCount() == 1);
-
- BasicBlock* taken = branchNode->branchData()->taken.block;
- BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
-
- bool invert = false;
- if (taken == nextBlock()) {
- invert = true;
- BasicBlock* tmp = taken;
- taken = notTaken;
- notTaken = tmp;
- }
-
- SpeculateCellOperand base(this, node->child1());
- SpeculateCellOperand argument(this, node->child2());
- GPRReg baseGPR = base.gpr();
- GPRReg argumentGPR = argument.gpr();
-
- flushRegisters();
- GPRFlushedCallResult result(this);
- callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
- m_jit.exceptionCheck();
-
- branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, result.gpr(), taken);
- jump(notTaken);
-
- use(node->child1());
- use(node->child2());
- m_indexInBlock = branchIndexInBlock;
- m_currentNode = branchNode;
-
- return true;
-}
-
void SpeculativeJIT::compileIsObjectOrNull(Node* node)
{
JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
}
case RegExpExec: {
- if (compileRegExpExec(node))
- return;
-
- if (!node->adjustedRefCount()) {
- SpeculateCellOperand base(this, node->child1());
- SpeculateCellOperand argument(this, node->child2());
- GPRReg baseGPR = base.gpr();
- GPRReg argumentGPR = argument.gpr();
-
- flushRegisters();
- GPRFlushedCallResult result(this);
- callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
- m_jit.exceptionCheck();
-
- // Must use jsValueResult because otherwise we screw up register
- // allocation, which thinks that this node has a result.
- booleanResult(result.gpr(), node);
- break;
- }
-
SpeculateCellOperand base(this, node->child1());
SpeculateCellOperand argument(this, node->child2());
GPRReg baseGPR = base.gpr();
}
case RegExpExec: {
- if (compileRegExpExec(node))
- return;
- if (!node->adjustedRefCount()) {
- SpeculateCellOperand base(this, node->child1());
- SpeculateCellOperand argument(this, node->child2());
- GPRReg baseGPR = base.gpr();
- GPRReg argumentGPR = argument.gpr();
-
- flushRegisters();
- GPRFlushedCallResult result(this);
- callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
- m_jit.exceptionCheck();
-
- // Must use jsValueResult because otherwise we screw up register
- // allocation, which thinks that this node has a result.
- jsValueResult(result.gpr(), node);
- break;
- }
-
SpeculateCellOperand base(this, node->child1());
SpeculateCellOperand argument(this, node->child2());
GPRReg baseGPR = base.gpr();
flushRegisters();
GPRFlushedCallResult result(this);
+ // FIXME: We really should be able to inline code that uses NewRegexp. That means not
+ // reaching into the CodeBlock here.
+ // https://bugs.webkit.org/show_bug.cgi?id=154808
callOperation(operationNewRegexp, result.gpr(), m_jit.codeBlock()->regexp(node->regexpIndex()));
m_jit.exceptionCheck();
case PutSetterByVal:
case CopyRest:
case GetRestLength:
+ case RegExpExec:
+ case RegExpTest:
+ case NewRegexp:
// These are OK.
break;
case GetRestLength:
compileGetRestLength();
break;
+ case RegExpExec:
+ compileRegExpExec();
+ break;
+ case RegExpTest:
+ compileRegExpTest();
+ break;
+ case NewRegexp:
+ compileNewRegexp();
+ break;
case PhantomLocal:
case LoopHint:
m_out.appendTo(continuation, lastNext);
}
+ void compileRegExpExec()
+ {
+ LValue base = lowCell(m_node->child1());
+ LValue argument = lowCell(m_node->child2());
+ setJSValue(
+ vmCall(Int64, m_out.operation(operationRegExpExec), m_callFrame, base, argument));
+ }
+
+ void compileRegExpTest()
+ {
+ LValue base = lowCell(m_node->child1());
+ LValue argument = lowCell(m_node->child2());
+ setBoolean(
+ vmCall(Int32, m_out.operation(operationRegExpTest), m_callFrame, base, argument));
+ }
+
+ void compileNewRegexp()
+ {
+ // FIXME: We really should be able to inline code that uses NewRegexp. That means not
+ // reaching into the CodeBlock here.
+ // https://bugs.webkit.org/show_bug.cgi?id=154808
+
+ LValue result = vmCall(
+ pointerType(),
+ m_out.operation(operationNewRegexp), m_callFrame,
+ m_out.constIntPtr(codeBlock()->regexp(m_node->regexpIndex())));
+
+ setJSValue(result);
+ }
+
LValue didOverflowStack()
{
// This does a very simple leaf function analysis. The invariant of FTL call
--- /dev/null
+function foo(s) {
+ return /foo/.exec(s);
+}
+
+noInline(foo);
+
+for (var i = 0; i < 100000; ++i) {
+ var result = foo("foo");
+ if (!result)
+ throw "Error: bad result for foo";
+ if (result.length != 1)
+ throw "Error: bad result for foo: " + result;
+ if (result[0] != "foo")
+ throw "Error: bad result for foo: " + result;
+ if (foo("bar"))
+ throw "Error: bad result for bar";
+}
--- /dev/null
+function foo(s) {
+ return /foo/.test(s);
+}
+
+noInline(foo);
+
+for (var i = 0; i < 100000; ++i) {
+ if (!foo("foo"))
+ throw "Error: bad result for foo";
+ if (foo("bar"))
+ throw "Error: bad result for bar";
+}