fourthTier: CFA should defend against results seeming inconsistent due to a watchpoint firing during compilation
https://bugs.webkit.org/show_bug.cgi?id=115083
Reviewed by Geoffrey Garen.
This ruggedizes our racyness with respect to watchpoints. We want to be able to assert,
in some places, that a watchpoint-based optimization has only occurred if the
watchpoint set was still valid. But currently we *can* soundly do watchpoint-based
optimizations even for invalid watchpoints, so long as we recorded in the IR that we
had done so; this will then lead to the code being insta-jettisoned after compilation
completes. Obviously, we don't want this to happen often - but we do want to allow it
precisely in the case of watchpoint races.
This adds the ability to assert that we hadn't over-watchpointed ourselves, with and
exemption for races.
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::executeEffects):
* dfg/DFGAbstractValue.cpp:
(JSC::DFG::AbstractValue::setFuturePossibleStructure):
(JSC::DFG::AbstractValue::filterFuturePossibleStructure):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addStructureTransitionCheck):
(JSC::DFG::ByteCodeParser::parseResolveOperations):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck):
* dfg/DFGDesiredWatchpoints.h:
(GenericDesiredWatchpoints):
(JSC::DFG::GenericDesiredWatchpoints::isStillValid):
(JSC::DFG::GenericDesiredWatchpoints::shouldAssumeMixedState):
(JSC::DFG::GenericDesiredWatchpoints::isValidOrMixed):
(JSC::DFG::DesiredWatchpoints::isStillValid):
(JSC::DFG::DesiredWatchpoints::shouldAssumeMixedState):
(JSC::DFG::DesiredWatchpoints::isValidOrMixed):
(DesiredWatchpoints):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::canOptimizeStringObjectAccess):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::masqueradesAsUndefinedWatchpointIsStillValid):
(Graph):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
(JSC::DFG::JITCompiler::compile):
(JSC::DFG::JITCompiler::compileFunction):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::addLazily):
(JITCompiler):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::masqueradesAsUndefinedWatchpointIsStillValid):
(JSC::DFG::SpeculativeJIT::speculationWatchpointForMasqueradesAsUndefined):
(JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCompile.cpp:
(JSC::FTL::compile):
* ftl/FTLState.h:
(State):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153130 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 240367c..ff976e5 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -558,7 +558,7 @@
}
case ArithIMul: {
- forNode(node).set(SpecInt32);
+ forNode(node).setType(SpecInt32);
break;
}
@@ -682,23 +682,18 @@
case IsString:
case IsObject:
case IsFunction: {
- node->setCanExit(node->op() == IsUndefined && m_codeBlock->globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid());
+ node->setCanExit(
+ node->op() == IsUndefined
+ && m_graph.masqueradesAsUndefinedWatchpointIsStillValid(node->codeOrigin));
JSValue child = forNode(node->child1()).value();
if (child) {
bool constantWasSet;
switch (node->op()) {
case IsUndefined:
- if (m_codeBlock->globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
- constantWasSet = trySetConstant(node, jsBoolean(
- child.isCell()
- ? false
- : child.isUndefined()));
- } else {
- constantWasSet = trySetConstant(node, jsBoolean(
- child.isCell()
- ? child.asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->codeOrigin))
- : child.isUndefined()));
- }
+ constantWasSet = trySetConstant(node, jsBoolean(
+ child.isCell()
+ ? child.asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->codeOrigin))
+ : child.isUndefined()));
break;
case IsBoolean:
constantWasSet = trySetConstant(node, jsBoolean(child.isBoolean()));
@@ -868,7 +863,7 @@
break;
case StringFromCharCode:
- forNode(node).set(SpecString);
+ forNode(node).setType(SpecString);
break;
case StringCharAt:
@@ -1007,7 +1002,7 @@
break;
case RegExpTest:
- forNode(node).set(SpecBoolean);
+ forNode(node).setType(SpecBoolean);
break;
case Jump:
@@ -1366,7 +1361,9 @@
// Currently, we only issue singleton watchpoints (that check one structure)
// and our futurePossibleStructure set can only contain zero, one, or an
// infinity of structures.
- ASSERT(value.m_futurePossibleStructure.isSubsetOf(StructureSet(node->structure())));
+ ASSERT(
+ value.m_futurePossibleStructure.isSubsetOf(StructureSet(node->structure()))
+ || m_graph.m_watchpoints.shouldAssumeMixedState(node->structure()->transitionWatchpointSet()));
value.filter(m_graph, node->structure());
m_haveStructures = true;