Commit 67e0f33a authored by oliver@apple.com's avatar oliver@apple.com

fourthTier: CFA should defend against results seeming inconsistent due to a...

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
parent fe0cc19e
2013-07-16 Oliver Hunt <oliver@apple.com>
Merge dfgFourthTier r149233
2013-04-26 Filip Pizlo <fpizlo@apple.com>
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):
2013-04-23 Filip Pizlo <fpizlo@apple.com>
fourthTier: AbstractValue methods that deal with watchpoints should have access to Graph, so that in debug mode, Graph can track the history of watchpoint states and detect races
......
......@@ -558,7 +558,7 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
}
case ArithIMul: {
forNode(node).set(SpecInt32);
forNode(node).setType(SpecInt32);
break;
}
......@@ -682,23 +682,18 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
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 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
break;
case StringFromCharCode:
forNode(node).set(SpecString);
forNode(node).setType(SpecString);
break;
case StringCharAt:
......@@ -1007,7 +1002,7 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
break;
case RegExpTest:
forNode(node).set(SpecBoolean);
forNode(node).setType(SpecBoolean);
break;
case Jump:
......@@ -1366,7 +1361,9 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
// 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;
......
......@@ -110,17 +110,17 @@ void AbstractValue::filter(Graph& graph, const StructureSet& other)
checkConsistency();
}
void AbstractValue::setFuturePossibleStructure(Graph&, Structure* structure)
void AbstractValue::setFuturePossibleStructure(Graph& graph, Structure* structure)
{
if (structure->transitionWatchpointSetIsStillValid())
if (graph.m_watchpoints.isStillValid(structure->transitionWatchpointSet()))
m_futurePossibleStructure = structure;
else
m_futurePossibleStructure.makeTop();
}
void AbstractValue::filterFuturePossibleStructure(Graph&, Structure* structure)
void AbstractValue::filterFuturePossibleStructure(Graph& graph, Structure* structure)
{
if (structure->transitionWatchpointSetIsStillValid())
if (graph.m_watchpoints.isStillValid(structure->transitionWatchpointSet()))
m_futurePossibleStructure.filter(StructureAbstractValue(structure));
}
......
......@@ -788,7 +788,8 @@ private:
// be jettisoned if the object ever dies.
Node* objectNode = cellConstant(object);
if (object->structure() == structure && structure->transitionWatchpointSetIsStillValid()) {
if (object->structure() == structure
&& m_graph.m_watchpoints.isStillValid(structure->transitionWatchpointSet())) {
addToGraph(StructureTransitionWatchpoint, OpInfo(structure), objectNode);
return objectNode;
}
......@@ -1917,7 +1918,7 @@ bool ByteCodeParser::parseResolveOperations(SpeculatedType prediction, unsigned
Identifier ident = m_codeBlock->identifier(identifier);
SymbolTableEntry entry = globalObject->symbolTable()->get(ident.impl());
if (!entry.couldBeWatched()) {
if (!m_graph.m_watchpoints.isStillValid(entry.watchpointSet())) {
*value = addToGraph(GetGlobalVar, OpInfo(globalObject->assertRegisterIsInThisObject(pc->m_registerAddress)), OpInfo(prediction));
return true;
}
......@@ -2638,6 +2639,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
addStructureTransitionCheck(prototype.asCell());
}
}
WTF::loadLoadFence();
ASSERT(putByIdStatus.oldStructure()->transitionWatchpointSetHasBeenInvalidated());
Node* propertyStorage;
......
......@@ -397,7 +397,7 @@ private:
Node* weakConstant = m_insertionSet.insertNode(
indexInBlock, speculationFromValue(cell), WeakJSConstant, codeOrigin, OpInfo(cell));
if (cell->structure()->transitionWatchpointSetIsStillValid()) {
if (m_graph.m_watchpoints.isStillValid(cell->structure()->transitionWatchpointSet())) {
m_insertionSet.insertNode(
indexInBlock, SpecNone, StructureTransitionWatchpoint, codeOrigin,
OpInfo(cell->structure()), Edge(weakConstant, CellUse));
......
......@@ -31,6 +31,7 @@
#if ENABLE(DFG_JIT)
#include "Watchpoint.h"
#include <wtf/HashMap.h>
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
......@@ -60,6 +61,9 @@ typedef WatchpointForGenericWatchpointSet<InlineWatchpointSet> WatchpointForInli
template<typename WatchpointSetType>
class GenericDesiredWatchpoints {
WTF_MAKE_NONCOPYABLE(GenericDesiredWatchpoints);
#if !ASSERT_DISABLED
typedef HashMap<WatchpointSetType*, bool> StateMap;
#endif
public:
GenericDesiredWatchpoints()
: m_reallyAdded(false)
......@@ -87,9 +91,46 @@ public:
}
return true;
}
#if ASSERT_DISABLED
bool isStillValid(WatchpointSetType* set)
{
return set->isStillValid();
}
bool shouldAssumeMixedState(WatchpointSetType*)
{
return true;
}
#else
bool isStillValid(WatchpointSetType* set)
{
bool result = set->isStillValid();
m_firstKnownState.add(set, result);
return result;
}
bool shouldAssumeMixedState(WatchpointSetType* set)
{
typename StateMap::iterator iter = m_firstKnownState.find(set);
if (iter == m_firstKnownState.end())
return false;
WTF::loadLoadFence();
return iter->value != set->isStillValid();
}
#endif
bool isValidOrMixed(WatchpointSetType* set)
{
return isStillValid(set) || shouldAssumeMixedState(set);
}
private:
Vector<WatchpointForGenericWatchpointSet<WatchpointSetType> > m_watchpoints;
#if !ASSERT_DISABLED
StateMap m_firstKnownState;
#endif
bool m_reallyAdded;
};
......@@ -105,6 +146,31 @@ public:
bool areStillValid() const;
bool isStillValid(WatchpointSet* set)
{
return m_sets.isStillValid(set);
}
bool isStillValid(InlineWatchpointSet& set)
{
return m_inlineSets.isStillValid(&set);
}
bool shouldAssumeMixedState(WatchpointSet* set)
{
return m_sets.shouldAssumeMixedState(set);
}
bool shouldAssumeMixedState(InlineWatchpointSet& set)
{
return m_inlineSets.shouldAssumeMixedState(&set);
}
bool isValidOrMixed(WatchpointSet* set)
{
return m_sets.isValidOrMixed(set);
}
bool isValidOrMixed(InlineWatchpointSet& set)
{
return m_inlineSets.isValidOrMixed(&set);
}
private:
GenericDesiredWatchpoints<WatchpointSet> m_sets;
GenericDesiredWatchpoints<InlineWatchpointSet> m_inlineSets;
......
......@@ -1112,7 +1112,7 @@ private:
JSObject* stringPrototypeObject = asObject(stringObjectStructure->storedPrototype());
Structure* stringPrototypeStructure = stringPrototypeObject->structure();
if (stringPrototypeStructure->transitionWatchpointSetHasBeenInvalidated())
if (!m_graph.m_watchpoints.isStillValid(stringPrototypeStructure->transitionWatchpointSet()))
return false;
if (stringPrototypeStructure->isDictionary())
......
......@@ -34,6 +34,7 @@
#include "DFGArgumentPosition.h"
#include "DFGAssemblyHelpers.h"
#include "DFGBasicBlock.h"
#include "DFGDesiredWatchpoints.h"
#include "DFGDominators.h"
#include "DFGLongLivedState.h"
#include "DFGNode.h"
......@@ -376,6 +377,12 @@ public:
return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock);
}
bool masqueradesAsUndefinedWatchpointIsStillValid(const CodeOrigin& codeOrigin)
{
return m_watchpoints.isStillValid(
globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint());
}
bool hasGlobalExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
{
return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(exitKind));
......@@ -719,6 +726,7 @@ public:
unsigned m_parameterSlots;
unsigned m_osrEntryBytecodeIndex;
Operands<JSValue> m_mustHandleValues;
DesiredWatchpoints m_watchpoints;
OptimizationFixpointState m_fixpointState;
GraphForm m_form;
......
......@@ -239,7 +239,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
m_jitCode->common.compilation = m_graph.m_compilation;
m_watchpoints.reallyAdd();
m_graph.m_watchpoints.reallyAdd();
}
bool JITCompiler::compile(RefPtr<JSC::JITCode>& entry)
......@@ -262,7 +262,7 @@ bool JITCompiler::compile(RefPtr<JSC::JITCode>& entry)
speculative.createOSREntries();
setEndOfCode();
if (!m_watchpoints.areStillValid())
if (!m_graph.m_watchpoints.areStillValid())
return false;
LinkBuffer linkBuffer(*m_vm, this, m_codeBlock, JITCompilationCanFail);
......@@ -355,7 +355,7 @@ bool JITCompiler::compileFunction(RefPtr<JSC::JITCode>& entry, MacroAssemblerCod
speculative.createOSREntries();
setEndOfCode();
if (!m_watchpoints.areStillValid())
if (!m_graph.m_watchpoints.areStillValid())
return false;
// === Link ===
......
......@@ -30,7 +30,6 @@
#include "CodeBlock.h"
#include "DFGCCallHelpers.h"
#include "DFGDesiredWatchpoints.h"
#include "DFGDisassembler.h"
#include "DFGFPRInfo.h"
#include "DFGGPRInfo.h"
......@@ -255,11 +254,11 @@ public:
void addLazily(Watchpoint* watchpoint, WatchpointSet* set)
{
m_watchpoints.addLazily(watchpoint, set);
m_graph.m_watchpoints.addLazily(watchpoint, set);
}
void addLazily(Watchpoint* watchpoint, InlineWatchpointSet& set)
{
m_watchpoints.addLazily(watchpoint, set);
m_graph.m_watchpoints.addLazily(watchpoint, set);
}
// Methods to set labels for the disassembler.
......@@ -479,8 +478,6 @@ private:
Vector<OSRExitCompilationInfo> m_exitCompilationInfo;
Vector<Vector<Label> > m_exitSiteLabels;
unsigned m_currentCodeOriginIndex;
DesiredWatchpoints m_watchpoints;
};
} } // namespace JSC::DFG
......
......@@ -1350,10 +1350,9 @@ void SpeculativeJIT::compilePeepHoleObjectEquality(Node* node, Node* branchNode)
GPRReg op1GPR = op1.gpr();
GPRReg op2GPR = op2.gpr();
if (m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint());
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
speculationWatchpointForMasqueradesAsUndefined();
if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
speculationCheck(
BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
......
......@@ -290,6 +290,25 @@ public:
}
return result;
}
bool masqueradesAsUndefinedWatchpointIsStillValid(const CodeOrigin& codeOrigin)
{
return m_jit.graph().masqueradesAsUndefinedWatchpointIsStillValid(codeOrigin);
}
void speculationWatchpointForMasqueradesAsUndefined(const CodeOrigin& codeOrigin)
{
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint());
}
bool masqueradesAsUndefinedWatchpointIsStillValid()
{
return masqueradesAsUndefinedWatchpointIsStillValid(m_currentNode->codeOrigin);
}
void speculationWatchpointForMasqueradesAsUndefined()
{
speculationWatchpointForMasqueradesAsUndefined(m_currentNode->codeOrigin);
}
static void writeBarrier(MacroAssembler&, GPRReg ownerGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, WriteBarrierUseKind);
......@@ -2856,7 +2875,7 @@ void SpeculativeJIT::speculateStringObjectForStructure(Edge edge, StructureLocat
Structure* stringObjectStructure =
m_jit.globalObjectFor(m_currentNode->codeOrigin)->stringObjectStructure();
Structure* stringPrototypeStructure = stringObjectStructure->storedPrototype().asCell()->structure();
ASSERT(stringPrototypeStructure->transitionWatchpointSetIsStillValid());
ASSERT(m_jit.graph().m_watchpoints.isValidOrMixed(stringPrototypeStructure->transitionWatchpointSet()));
if (!m_state.forNode(edge).m_currentKnownStructure.isSubsetOf(StructureSet(m_jit.globalObjectFor(m_currentNode->codeOrigin)->stringObjectStructure()))) {
speculationCheck(
......@@ -2864,7 +2883,9 @@ void SpeculativeJIT::speculateStringObjectForStructure(Edge edge, StructureLocat
m_jit.branchPtr(
JITCompiler::NotEqual, structureLocation, TrustedImmPtr(stringObjectStructure)));
}
stringPrototypeStructure->addTransitionWatchpoint(speculationWatchpoint(NotStringObject));
m_jit.addLazily(
speculationWatchpoint(NotStringObject),
stringPrototypeStructure->transitionWatchpointSet());
}
#define DFG_TYPE_CHECK(source, edge, typesPassedThrough, jumpToFail) do { \
......
......@@ -387,13 +387,11 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv
JITCompiler::Jump notCell;
JITCompiler::Jump notMasqueradesAsUndefined;
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
if (!isKnownCell(operand.node()))
notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
speculationWatchpointForMasqueradesAsUndefined();
m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR);
notMasqueradesAsUndefined = m_jit.jump();
} else {
......@@ -456,13 +454,11 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branch
JITCompiler::Jump notCell;
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
if (!isKnownCell(operand.node()))
notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
speculationWatchpointForMasqueradesAsUndefined();
jump(invert ? taken : notTaken, ForceJump);
} else {
GPRTemporary localGlobalObject(this);
......@@ -1287,10 +1283,8 @@ void SpeculativeJIT::compileObjectEquality(Node* node)
GPRReg op1GPR = op1.gpr();
GPRReg op2GPR = op2.gpr();
if (m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint());
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
speculationWatchpointForMasqueradesAsUndefined();
DFG_TYPE_CHECK(
JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
MacroAssembler::Equal,
......@@ -1356,7 +1350,8 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r
GPRTemporary structure;
GPRReg structureGPR = InvalidGPRReg;
bool masqueradesAsUndefinedWatchpointValid = m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid();
bool masqueradesAsUndefinedWatchpointValid =
masqueradesAsUndefinedWatchpointIsStillValid();
if (!masqueradesAsUndefinedWatchpointValid) {
// The masquerades as undefined case will use the structure register, so allocate it here.
......@@ -1367,9 +1362,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r
}
if (masqueradesAsUndefinedWatchpointValid) {
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
speculationWatchpointForMasqueradesAsUndefined();
DFG_TYPE_CHECK(
JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
MacroAssembler::Equal,
......@@ -1397,9 +1390,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r
// We know that within this branch, rightChild must be a cell.
if (masqueradesAsUndefinedWatchpointValid) {
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
speculationWatchpointForMasqueradesAsUndefined();
DFG_TYPE_CHECK(
JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
m_jit.branchPtr(
......@@ -1468,7 +1459,8 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
GPRTemporary structure;
GPRReg structureGPR = InvalidGPRReg;
bool masqueradesAsUndefinedWatchpointValid = m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid();
bool masqueradesAsUndefinedWatchpointValid =
masqueradesAsUndefinedWatchpointIsStillValid();
if (!masqueradesAsUndefinedWatchpointValid) {
// The masquerades as undefined case will use the structure register, so allocate it here.
......@@ -1479,9 +1471,7 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
}
if (masqueradesAsUndefinedWatchpointValid) {
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
speculationWatchpointForMasqueradesAsUndefined();
DFG_TYPE_CHECK(
JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
MacroAssembler::Equal,
......@@ -1508,9 +1498,7 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
// We know that within this branch, rightChild must be a cell.
if (masqueradesAsUndefinedWatchpointValid) {
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
speculationWatchpointForMasqueradesAsUndefined();
DFG_TYPE_CHECK(
JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
m_jit.branchPtr(
......@@ -1616,7 +1604,8 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
GPRTemporary structure;
GPRReg structureGPR = InvalidGPRReg;
bool masqueradesAsUndefinedWatchpointValid = m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid();
bool masqueradesAsUndefinedWatchpointValid =
masqueradesAsUndefinedWatchpointIsStillValid();
if (!masqueradesAsUndefinedWatchpointValid) {
// The masquerades as undefined case will use the structure register, so allocate it here.
......@@ -1628,9 +1617,7 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
if (masqueradesAsUndefinedWatchpointValid) {
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
speculationWatchpointForMasqueradesAsUndefined();
DFG_TYPE_CHECK(
JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
......@@ -1759,11 +1746,8 @@ void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, Blo
GPRReg scratchGPR = scratch.gpr();
MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
speculationWatchpointForMasqueradesAsUndefined();
DFG_TYPE_CHECK(
JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
m_jit.branchPtr(
......@@ -4321,10 +4305,8 @@ void SpeculativeJIT::compile(Node* node)
isCell.link(&m_jit);
JITCompiler::Jump notMasqueradesAsUndefined;
if (m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.addLazily(
speculationWatchpoint(),
m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint());
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
speculationWatchpointForMasqueradesAsUndefined();
m_jit.move(TrustedImm32(0), result.gpr());
notMasqueradesAsUndefined = m_jit.jump();
} else {
......