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;