Merge r169148, r169185, r169188, r169578, r169582, r169584, r169588, r169753 from...
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 23 Jul 2014 01:19:50 +0000 (01:19 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 23 Jul 2014 01:19:50 +0000 (01:19 +0000)
Source/JavaScriptCore:

Note that r169753 is merged out of order because it fixes a bug in r169588.

    2014-06-10  Filip Pizlo  <fpizlo@apple.com>

    [ftlopt] Structure::dfgShouldWatchIfPossible() is unsound
    https://bugs.webkit.org/show_bug.cgi?id=133624

    Reviewed by Mark Hahnenberg.

    * runtime/Structure.h:
    (JSC::Structure::dfgShouldWatchIfPossible): Make it sound and add some verbiage.

    2014-06-04  Filip Pizlo  <fpizlo@apple.com>

    [ftlopt] AI should be able track structure sets larger than 1
    https://bugs.webkit.org/show_bug.cgi?id=128073

    Reviewed by Oliver Hunt.

    This makes two major changes to how AI (abstract interpreter) proves that a value has
    some structure:

    - StructureAbstractValue can now track an arbitrary number of structures. A set whose
      size is greater than one means that the value may have any of the structures, and we
      don't know which - but we do know that it cannot be any structure not in the set. The
      structure abstract value can still be TOP, which means the set of all structures. We
      artificially limit the set size to StructureAbstractValue::polymorphismLimit to guard
      memory explosion on pathological programs. This limit is big enough that it wouldn't
      kick in for normal code, since we have other heuristics that limit the number of
      structures that we would allow an inline cache to know about.

    - We eagerly set watchpoints on all watchable structures and then we assume that
      watchable structures are being watched, and that the watchpoint will jettison the code.
      This allows tracking of watchable structures to be far simpler than before. Previously,
      a structure being tracked as "future possible" was predicated on it being watchable but
      we might not actually watch it. This makes algebra over sets of future possible
      structures quite weird. But watching all watchable structures means that we simple say
      that a structure set can be in the following states: unclobbered, which means it's just
      a set of structures and it doesn't matter what is watchable or what isn't because we've
      proven that the value must have one of these structures right now; and clobbered, which
      means that we have a set of structures, plus all possible structures temporarily, with
      invalidation removing the "plus all possible structures". Clobbering a set means that
      if any of its structures are unwatchable, the set just becomes TOP; but if all
      structures in the set are watchable then we just set the clobbered bit to add the "plus
      all possible structures temporarily" thing. This precisely tracks the exact meaning of
      watchability and invalidation points.

    Slight SunSpider slow-down, neutral on Octane, slight AsmBench speed-up. I believe that
    we will ultimately undo the SunSpider slow-down by making further improvements to the set
    representation. I believe that Octane perfromance will ultimately improve once we remove
    remaining singleton special-cases. The ultimate goal of this is to remove the need to
    try quite so desperately hard to make everything monomorphic as we do currently.

    * CMakeLists.txt:
    * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
    * JavaScriptCore.xcodeproj/project.pbxproj:
    * bytecode/StructureSet.cpp:
    (JSC::StructureSet::clear):
    (JSC::StructureSet::remove):
    (JSC::StructureSet::filter):
    (JSC::StructureSet::copyFromOutOfLine):
    (JSC::StructureSet::StructureSet): Deleted.
    (JSC::StructureSet::operator=): Deleted.
    (JSC::StructureSet::copyFrom): Deleted.
    * bytecode/StructureSet.h:
    (JSC::StructureSet::StructureSet):
    (JSC::StructureSet::operator=):
    (JSC::StructureSet::isEmpty):
    (JSC::StructureSet::genericFilter):
    (JSC::StructureSet::ContainsOutOfLine::ContainsOutOfLine):
    (JSC::StructureSet::ContainsOutOfLine::operator()):
    (JSC::StructureSet::copyFrom):
    (JSC::StructureSet::deleteStructureListIfNecessary):
    (JSC::StructureSet::setEmpty):
    (JSC::StructureSet::getReservedFlag):
    (JSC::StructureSet::setReservedFlag):
    * dfg/DFGAbstractInterpreter.h:
    (JSC::DFG::AbstractInterpreter::setBuiltInConstant):
    * dfg/DFGAbstractInterpreterInlines.h:
    (JSC::DFG::AbstractInterpreter<AbstractStateType>::booleanResult):
    (JSC::DFG::AbstractInterpreter<AbstractStateType>::verifyEdge):
    (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
    (JSC::DFG::AbstractInterpreter<AbstractStateType>::clobberCapturedVars):
    (JSC::DFG::AbstractInterpreter<AbstractStateType>::forAllValues):
    (JSC::DFG::AbstractInterpreter<AbstractStateType>::clobberStructures):
    (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransition):
    (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransitions):
    (JSC::DFG::AbstractInterpreter<AbstractStateType>::setDidClobber):
    (JSC::DFG::AbstractInterpreter<AbstractStateType>::dump):
    * dfg/DFGAbstractValue.cpp:
    (JSC::DFG::AbstractValue::observeTransitions):
    (JSC::DFG::AbstractValue::setMostSpecific):
    (JSC::DFG::AbstractValue::set):
    (JSC::DFG::AbstractValue::filter):
    (JSC::DFG::AbstractValue::shouldBeClear):
    (JSC::DFG::AbstractValue::normalizeClarity):
    (JSC::DFG::AbstractValue::checkConsistency):
    (JSC::DFG::AbstractValue::assertIsWatched):
    (JSC::DFG::AbstractValue::dumpInContext):
    (JSC::DFG::AbstractValue::setFuturePossibleStructure): Deleted.
    * dfg/DFGAbstractValue.h:
    (JSC::DFG::AbstractValue::clear):
    (JSC::DFG::AbstractValue::clobberStructures):
    (JSC::DFG::AbstractValue::clobberStructuresFor):
    (JSC::DFG::AbstractValue::observeInvalidationPoint):
    (JSC::DFG::AbstractValue::observeInvalidationPointFor):
    (JSC::DFG::AbstractValue::observeTransition):
    (JSC::DFG::AbstractValue::TransitionObserver::TransitionObserver):
    (JSC::DFG::AbstractValue::TransitionObserver::operator()):
    (JSC::DFG::AbstractValue::TransitionsObserver::TransitionsObserver):
    (JSC::DFG::AbstractValue::TransitionsObserver::operator()):
    (JSC::DFG::AbstractValue::isHeapTop):
    (JSC::DFG::AbstractValue::setType):
    (JSC::DFG::AbstractValue::operator==):
    (JSC::DFG::AbstractValue::merge):
    (JSC::DFG::AbstractValue::validate):
    (JSC::DFG::AbstractValue::hasClobberableState):
    (JSC::DFG::AbstractValue::assertIsWatched):
    (JSC::DFG::AbstractValue::observeIndexingTypeTransition):
    (JSC::DFG::AbstractValue::makeTop):
    (JSC::DFG::AbstractValue::bestProvenStructure): Deleted.
    * dfg/DFGAllocator.h:
    * dfg/DFGArgumentsSimplificationPhase.cpp:
    (JSC::DFG::ArgumentsSimplificationPhase::run):
    * dfg/DFGArrayMode.cpp:
    (JSC::DFG::ArrayMode::alreadyChecked):
    * dfg/DFGAtTailAbstractState.h:
    (JSC::DFG::AtTailAbstractState::structureClobberState):
    (JSC::DFG::AtTailAbstractState::setStructureClobberState):
    (JSC::DFG::AtTailAbstractState::setFoundConstants):
    (JSC::DFG::AtTailAbstractState::haveStructures): Deleted.
    (JSC::DFG::AtTailAbstractState::setHaveStructures): Deleted.
    * dfg/DFGBasicBlock.cpp:
    (JSC::DFG::BasicBlock::BasicBlock):
    * dfg/DFGBasicBlock.h:
    * dfg/DFGBranchDirection.h:
    (JSC::DFG::branchDirectionToString):
    (WTF::printInternal):
    * dfg/DFGByteCodeParser.cpp:
    (JSC::DFG::ByteCodeParser::handlePutById):
    * dfg/DFGCFAPhase.cpp:
    (JSC::DFG::CFAPhase::performBlockCFA):
    * dfg/DFGCSEPhase.cpp:
    (JSC::DFG::CSEPhase::checkStructureElimination):
    (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
    (JSC::DFG::CSEPhase::performNodeCSE):
    * dfg/DFGClobberize.h:
    (JSC::DFG::clobberize):
    * dfg/DFGCommon.cpp:
    (JSC::DFG::startCrashing):
    (JSC::DFG::isCrashing):
    * dfg/DFGCommon.h:
    * dfg/DFGCommonData.cpp:
    (JSC::DFG::CommonData::notifyCompilingStructureTransition):
    * dfg/DFGConstantFoldingPhase.cpp:
    (JSC::DFG::ConstantFoldingPhase::foldConstants):
    (JSC::DFG::ConstantFoldingPhase::emitGetByOffset):
    (JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
    (JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck):
    * dfg/DFGDesiredWatchpoints.cpp:
    (JSC::DFG::DesiredWatchpoints::consider):
    (JSC::DFG::DesiredWatchpoints::addLazily): Deleted.
    * dfg/DFGDesiredWatchpoints.h:
    (JSC::DFG::GenericDesiredWatchpoints::reallyAdd):
    (JSC::DFG::GenericDesiredWatchpoints::areStillValid):
    (JSC::DFG::GenericDesiredWatchpoints::isWatched):
    (JSC::DFG::DesiredWatchpoints::isWatched):
    (JSC::DFG::WatchpointForGenericWatchpointSet::WatchpointForGenericWatchpointSet): Deleted.
    (JSC::DFG::GenericDesiredWatchpoints::addLazily): Deleted.
    (JSC::DFG::GenericDesiredWatchpoints::isStillValid): Deleted.
    (JSC::DFG::GenericDesiredWatchpoints::shouldAssumeMixedState): Deleted.
    (JSC::DFG::GenericDesiredWatchpoints::isValidOrMixed): Deleted.
    (JSC::DFG::DesiredWatchpoints::isStillValid): Deleted.
    (JSC::DFG::DesiredWatchpoints::shouldAssumeMixedState): Deleted.
    (JSC::DFG::DesiredWatchpoints::isValidOrMixed): Deleted.
    * dfg/DFGDoesGC.cpp:
    (JSC::DFG::doesGC):
    * dfg/DFGFixupPhase.cpp:
    (JSC::DFG::FixupPhase::fixupNode):
    (JSC::DFG::FixupPhase::canOptimizeStringObjectAccess):
    (JSC::DFG::FixupPhase::injectTypeConversionsForEdge):
    * dfg/DFGGraph.cpp:
    (JSC::DFG::Graph::~Graph):
    (JSC::DFG::Graph::dump):
    (JSC::DFG::Graph::dumpBlockHeader):
    (JSC::DFG::Graph::tryGetFoldableView):
    (JSC::DFG::Graph::visitChildren):
    (JSC::DFG::Graph::assertIsWatched):
    (JSC::DFG::Graph::handleAssertionFailure):
    * dfg/DFGGraph.h:
    (JSC::DFG::Graph::convertToConstant):
    (JSC::DFG::Graph::masqueradesAsUndefinedWatchpointIsStillValid):
    (JSC::DFG::Graph::addStructureTransitionData): Deleted.
    * dfg/DFGInPlaceAbstractState.cpp:
    (JSC::DFG::InPlaceAbstractState::beginBasicBlock):
    (JSC::DFG::InPlaceAbstractState::initialize):
    (JSC::DFG::InPlaceAbstractState::endBasicBlock):
    (JSC::DFG::InPlaceAbstractState::reset):
    (JSC::DFG::InPlaceAbstractState::merge):
    * dfg/DFGInPlaceAbstractState.h:
    (JSC::DFG::InPlaceAbstractState::structureClobberState):
    (JSC::DFG::InPlaceAbstractState::setStructureClobberState):
    (JSC::DFG::InPlaceAbstractState::setFoundConstants):
    (JSC::DFG::InPlaceAbstractState::haveStructures): Deleted.
    (JSC::DFG::InPlaceAbstractState::setHaveStructures): Deleted.
    * dfg/DFGLivenessAnalysisPhase.cpp:
    (JSC::DFG::LivenessAnalysisPhase::run):
    * dfg/DFGNode.h:
    (JSC::DFG::Node::hasTransition):
    (JSC::DFG::Node::transition):
    (JSC::DFG::Node::hasStructure):
    (JSC::DFG::StructureTransitionData::StructureTransitionData): Deleted.
    (JSC::DFG::Node::convertToStructureTransitionWatchpoint): Deleted.
    (JSC::DFG::Node::hasStructureTransitionData): Deleted.
    (JSC::DFG::Node::structureTransitionData): Deleted.
    * dfg/DFGNodeType.h:
    * dfg/DFGPlan.cpp:
    (JSC::DFG::Plan::compileInThreadImpl):
    * dfg/DFGPredictionPropagationPhase.cpp:
    (JSC::DFG::PredictionPropagationPhase::propagate):
    * dfg/DFGSafeToExecute.h:
    (JSC::DFG::safeToExecute):
    * dfg/DFGSpeculativeJIT.cpp:
    (JSC::DFG::SpeculativeJIT::compileAllocatePropertyStorage):
    (JSC::DFG::SpeculativeJIT::compileReallocatePropertyStorage):
    * dfg/DFGSpeculativeJIT.h:
    (JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure):
    * dfg/DFGSpeculativeJIT32_64.cpp:
    (JSC::DFG::SpeculativeJIT::compile):
    * dfg/DFGSpeculativeJIT64.cpp:
    (JSC::DFG::SpeculativeJIT::compile):
    * dfg/DFGStructureAbstractValue.cpp: Added.
    (JSC::DFG::StructureAbstractValue::assertIsWatched):
    (JSC::DFG::StructureAbstractValue::clobber):
    (JSC::DFG::StructureAbstractValue::observeTransition):
    (JSC::DFG::StructureAbstractValue::observeTransitions):
    (JSC::DFG::StructureAbstractValue::add):
    (JSC::DFG::StructureAbstractValue::merge):
    (JSC::DFG::StructureAbstractValue::mergeSlow):
    (JSC::DFG::StructureAbstractValue::mergeNotTop):
    (JSC::DFG::StructureAbstractValue::filter):
    (JSC::DFG::StructureAbstractValue::filterSlow):
    (JSC::DFG::StructureAbstractValue::contains):
    (JSC::DFG::StructureAbstractValue::isSubsetOf):
    (JSC::DFG::StructureAbstractValue::isSupersetOf):
    (JSC::DFG::StructureAbstractValue::overlaps):
    (JSC::DFG::StructureAbstractValue::equalsSlow):
    (JSC::DFG::StructureAbstractValue::dumpInContext):
    (JSC::DFG::StructureAbstractValue::dump):
    * dfg/DFGStructureAbstractValue.h:
    (JSC::DFG::StructureAbstractValue::StructureAbstractValue):
    (JSC::DFG::StructureAbstractValue::operator=):
    (JSC::DFG::StructureAbstractValue::clear):
    (JSC::DFG::StructureAbstractValue::makeTop):
    (JSC::DFG::StructureAbstractValue::assertIsWatched):
    (JSC::DFG::StructureAbstractValue::observeInvalidationPoint):
    (JSC::DFG::StructureAbstractValue::top):
    (JSC::DFG::StructureAbstractValue::isClear):
    (JSC::DFG::StructureAbstractValue::isTop):
    (JSC::DFG::StructureAbstractValue::isNeitherClearNorTop):
    (JSC::DFG::StructureAbstractValue::isClobbered):
    (JSC::DFG::StructureAbstractValue::merge):
    (JSC::DFG::StructureAbstractValue::filter):
    (JSC::DFG::StructureAbstractValue::operator==):
    (JSC::DFG::StructureAbstractValue::size):
    (JSC::DFG::StructureAbstractValue::at):
    (JSC::DFG::StructureAbstractValue::operator[]):
    (JSC::DFG::StructureAbstractValue::onlyStructure):
    (JSC::DFG::StructureAbstractValue::isSupersetOf):
    (JSC::DFG::StructureAbstractValue::makeTopWhenThin):
    (JSC::DFG::StructureAbstractValue::setClobbered):
    (JSC::DFG::StructureAbstractValue::add): Deleted.
    (JSC::DFG::StructureAbstractValue::addAll): Deleted.
    (JSC::DFG::StructureAbstractValue::contains): Deleted.
    (JSC::DFG::StructureAbstractValue::isSubsetOf): Deleted.
    (JSC::DFG::StructureAbstractValue::doesNotContainAnyOtherThan): Deleted.
    (JSC::DFG::StructureAbstractValue::isClearOrTop): Deleted.
    (JSC::DFG::StructureAbstractValue::last): Deleted.
    (JSC::DFG::StructureAbstractValue::speculationFromStructures): Deleted.
    (JSC::DFG::StructureAbstractValue::isValidOffset): Deleted.
    (JSC::DFG::StructureAbstractValue::hasSingleton): Deleted.
    (JSC::DFG::StructureAbstractValue::singleton): Deleted.
    (JSC::DFG::StructureAbstractValue::dumpInContext): Deleted.
    (JSC::DFG::StructureAbstractValue::dump): Deleted.
    (JSC::DFG::StructureAbstractValue::topValue): Deleted.
    * dfg/DFGStructureClobberState.h: Added.
    (JSC::DFG::merge):
    (WTF::printInternal):
    * dfg/DFGTransition.cpp: Added.
    (JSC::DFG::Transition::dumpInContext):
    (JSC::DFG::Transition::dump):
    * dfg/DFGTransition.h: Added.
    (JSC::DFG::Transition::Transition):
    * dfg/DFGTypeCheckHoistingPhase.cpp:
    (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
    (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):
    * dfg/DFGWatchableStructureWatchingPhase.cpp: Added.
    (JSC::DFG::WatchableStructureWatchingPhase::WatchableStructureWatchingPhase):
    (JSC::DFG::WatchableStructureWatchingPhase::run):
    (JSC::DFG::WatchableStructureWatchingPhase::tryWatch):
    (JSC::DFG::performWatchableStructureWatching):
    * dfg/DFGWatchableStructureWatchingPhase.h: Added.
    * dfg/DFGWatchpointCollectionPhase.cpp:
    (JSC::DFG::WatchpointCollectionPhase::handle):
    (JSC::DFG::WatchpointCollectionPhase::handleEdge): Deleted.
    * ftl/FTLCapabilities.cpp:
    (JSC::FTL::canCompile):
    * ftl/FTLIntrinsicRepository.h:
    * ftl/FTLLowerDFGToLLVM.cpp:
    (JSC::FTL::ftlUnreachable):
    (JSC::FTL::LowerDFGToLLVM::createPhiVariables):
    (JSC::FTL::LowerDFGToLLVM::compileBlock):
    (JSC::FTL::LowerDFGToLLVM::compileNode):
    (JSC::FTL::LowerDFGToLLVM::compileUpsilon):
    (JSC::FTL::LowerDFGToLLVM::compilePhi):
    (JSC::FTL::LowerDFGToLLVM::compileDoubleRep):
    (JSC::FTL::LowerDFGToLLVM::compileValueRep):
    (JSC::FTL::LowerDFGToLLVM::compileValueToInt32):
    (JSC::FTL::LowerDFGToLLVM::compileGetArgument):
    (JSC::FTL::LowerDFGToLLVM::compileGetLocal):
    (JSC::FTL::LowerDFGToLLVM::compileSetLocal):
    (JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub):
    (JSC::FTL::LowerDFGToLLVM::compileArithMul):
    (JSC::FTL::LowerDFGToLLVM::compileArithDiv):
    (JSC::FTL::LowerDFGToLLVM::compileArithMod):
    (JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax):
    (JSC::FTL::LowerDFGToLLVM::compileArithAbs):
    (JSC::FTL::LowerDFGToLLVM::compileArithNegate):
    (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure):
    (JSC::FTL::LowerDFGToLLVM::compilePutStructure):
    (JSC::FTL::LowerDFGToLLVM::compileGetById):
    (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentsLength):
    (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal):
    (JSC::FTL::LowerDFGToLLVM::compileGetArrayLength):
    (JSC::FTL::LowerDFGToLLVM::compileGetByVal):
    (JSC::FTL::LowerDFGToLLVM::compilePutByVal):
    (JSC::FTL::LowerDFGToLLVM::compileArrayPush):
    (JSC::FTL::LowerDFGToLLVM::compileArrayPop):
    (JSC::FTL::LowerDFGToLLVM::compileNewArray):
    (JSC::FTL::LowerDFGToLLVM::compileNewArrayBuffer):
    (JSC::FTL::LowerDFGToLLVM::compileAllocatePropertyStorage):
    (JSC::FTL::LowerDFGToLLVM::compileReallocatePropertyStorage):
    (JSC::FTL::LowerDFGToLLVM::compileToString):
    (JSC::FTL::LowerDFGToLLVM::compileMakeRope):
    (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
    (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset):
    (JSC::FTL::LowerDFGToLLVM::compileCompareEq):
    (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
    (JSC::FTL::LowerDFGToLLVM::compileSwitch):
    (JSC::FTL::LowerDFGToLLVM::compare):
    (JSC::FTL::LowerDFGToLLVM::boolify):
    (JSC::FTL::LowerDFGToLLVM::terminate):
    (JSC::FTL::LowerDFGToLLVM::lowInt32):
    (JSC::FTL::LowerDFGToLLVM::lowInt52):
    (JSC::FTL::LowerDFGToLLVM::opposite):
    (JSC::FTL::LowerDFGToLLVM::lowCell):
    (JSC::FTL::LowerDFGToLLVM::lowBoolean):
    (JSC::FTL::LowerDFGToLLVM::lowDouble):
    (JSC::FTL::LowerDFGToLLVM::lowJSValue):
    (JSC::FTL::LowerDFGToLLVM::speculate):
    (JSC::FTL::LowerDFGToLLVM::isArrayType):
    (JSC::FTL::LowerDFGToLLVM::speculateStringObjectForStructureID):
    (JSC::FTL::LowerDFGToLLVM::callCheck):
    (JSC::FTL::LowerDFGToLLVM::buildExitArguments):
    (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
    (JSC::FTL::LowerDFGToLLVM::setInt52):
    (JSC::FTL::LowerDFGToLLVM::crash):
    (JSC::FTL::LowerDFGToLLVM::compileStructureTransitionWatchpoint): Deleted.
    * ftl/FTLOutput.cpp:
    (JSC::FTL::Output::crashNonTerminal): Deleted.
    * ftl/FTLOutput.h:
    (JSC::FTL::Output::crash): Deleted.
    * jit/JITOperations.h:
    * jsc.cpp:
    (WTF::jscExit):
    (functionQuit):
    (main):
    (printUsageStatement):
    (CommandLine::parseArguments):
    * runtime/Structure.h:
    (JSC::Structure::dfgShouldWatchIfPossible):
    (JSC::Structure::dfgShouldWatch):
    * tests/stress/arrayify-to-structure-contradiction.js: Added.
    (foo):
    * tests/stress/ftl-getmyargumentslength-inline.js: Added.
    (foo):
    * tests/stress/multi-put-by-offset-multiple-transitions.js: Added.
    (foo):
    (Foo):
    * tests/stress/throw-from-ftl-in-loop.js: Added.
    * tests/stress/throw-from-ftl.js: Added.
    (foo):

    2014-06-03  Filip Pizlo  <fpizlo@apple.com>

    [ftlopt] Unreviewed, roll out r169578. The build system needs some more love.

    * InlineRuntimeSymbolTable.h: Removed.
    * JavaScriptCore.xcodeproj/project.pbxproj:
    * build-symbol-table-index.py:
    * build-symbol-table-index.sh:
    * copy-llvm-ir-to-derived-sources.sh:
    * dfg/DFGByteCodeParser.cpp:
    (JSC::DFG::ByteCodeParser::handleCall):
    * dfg/DFGNode.h:
    (JSC::DFG::Node::canBeKnownFunction): Deleted.
    (JSC::DFG::Node::hasKnownFunction): Deleted.
    (JSC::DFG::Node::knownFunction): Deleted.
    (JSC::DFG::Node::giveKnownFunction): Deleted.
    * ftl/FTLAbbreviatedTypes.h:
    * ftl/FTLCompile.cpp:
    (JSC::FTL::compile):
    * ftl/FTLLowerDFGToLLVM.cpp:
    (JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
    (JSC::FTL::LowerDFGToLLVM::lower):
    (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct):
    (JSC::FTL::LowerDFGToLLVM::possiblyCompileInlineableNativeCall): Deleted.
    (JSC::FTL::LowerDFGToLLVM::getFunctionBySymbol): Deleted.
    (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): Deleted.
    (JSC::FTL::LowerDFGToLLVM::isInlinableSize): Deleted.
    * ftl/FTLState.cpp:
    (JSC::FTL::State::State):
    * ftl/FTLState.h:
    * heap/HandleStack.h:
    * llvm/InitializeLLVM.h:
    * llvm/InitializeLLVMMac.cpp: Removed.
    * llvm/InitializeLLVMMac.mm: Added.
    (JSC::initializeLLVMImpl):
    * llvm/LLVMAPIFunctions.h:
    * llvm/LLVMHeaders.h:
    * runtime/BundlePath.h: Removed.
    * runtime/BundlePath.mm: Removed.
    * runtime/DateConversion.h:
    * runtime/DateInstance.h:
    * runtime/ExceptionHelpers.h:
    * runtime/JSArray.h:
    * runtime/JSCJSValue.h:
    (JSC::JSValue::toFloat):
    * runtime/JSDateMath.h:
    * runtime/JSObject.h:
    * runtime/JSWrapperObject.h:
    * runtime/Options.h:
    * runtime/RegExp.h:
    * runtime/StringObject.h:
    * runtime/Structure.h:
    * tested-symbols.symlst: Removed.

    2014-06-03  Filip Pizlo  <fpizlo@apple.com>

    [ftlopt] FTL native inlining tests take far too long
    https://bugs.webkit.org/show_bug.cgi?id=133498

    Unreviewed test gardening.

    Added a new exceptions test since the other one appears to not work.

    * tests/stress/ftl-library-exception.js:
    * tests/stress/ftl-library-inline-gettimezoneoffset.js: Added.
    (foo):
    * tests/stress/ftl-library-inlining-exceptions-dataview.js: Added.
    (foo):
    * tests/stress/ftl-library-inlining-exceptions.js: Copied from LayoutTests/js/regress/script-tests/ftl-library-inlining-exceptions.js.
    * tests/stress/ftl-library-inlining-loops.js: Copied from LayoutTests/js/regress/script-tests/ftl-library-inlining-loops.js.
    * tests/stress/ftl-library-inlining-random.js:
    * tests/stress/ftl-library-substring.js:

    2014-06-03  Matthew Mirman  <mmirman@apple.com>

    [ftlopt] Added system for inlining native functions via the FTL.
    https://bugs.webkit.org/show_bug.cgi?id=131515

    Reviewed by Filip Pizlo.

    Also fixed the build to not compress the bitcode and to
    include all of the relevant runtime. With GCC_GENERATE_DEBUGGING_SYMBOLS = NO,
    the produced bitcode files are a 100th the size they were before.
    Now we can include all of the relevant runtime files with only a 3mb overhead.
    This is the same overhead as for two compressed files before,
    but done more efficiently (on both ends) and with less code.

    Deciding whether to inline native functions is left up to LLVM.
    The entire module containing the function is linked into the current
    compiled JS so that inlining the native functions shouldn't make them smaller.

    Rather than loading Runtime.symtbl at runtime FTLState.cpp now includes a file
    InlineRuntimeSymbolTable.h which statically builds the symbol table hash table.
    Currently build-symbol-table-index.py updates this file from the
    contents of tested-symbols.symlst when done building as a matter of convenience.
    However, in order to include the new contents of the file in the build
    you'd need to build twice.  This will be fixed in future versions.

    * JavaScriptCore.xcodeproj/project.pbxproj: Added back runtime files to compile.
    * build-symbol-table-index.py: Changed bitcode suffix.
    Added inclusion of only tested symbols.
    Added output to InlineRuntimeSymbolTable.h.
    * build-symbol-table-index.sh: Changed bitcode suffix.
    * copy-llvm-ir-to-derived-sources.sh: Removed gzip compression.
    * tested-symbols.symlst: Added.
    * dfg/DFGByteCodeParser.cpp:
    (JSC::DFG::ByteCodeParser::handleCall):
    Now sets the knownFunction of the call node if such a function exists
    and emits a check that during runtime the callee is in fact known.
    * dfg/DFGNode.h:
    Added functions to set the known function of a call node.
    (JSC::DFG::Node::canBeKnownFunction): Added.
    (JSC::DFG::Node::hasKnownFunction): Added.
    (JSC::DFG::Node::knownFunction): Added.
    (JSC::DFG::Node::giveKnownFunction): Added.
    * ftl/FTLAbbreviatedTypes.h: Added a typedef for LLVMMemoryBufferRef
    * ftl/FTLLowerDFGToLLVM.cpp:
    (JSC::FTL::LowerDFGToLLVM::isInlinableSize): Added. Hardcoded threshold to 275.
    (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): Added.
    (JSC::FTL::LowerDFGToLLVM::getFunctionBySymbol): Added.
    (JSC::FTL::LowerDFGToLLVM::possiblyCompileInlineableNativeCall): Added.
    (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct):
    Added call to possiblyCompileInlineableNativeCall
    * ftl/FTLOutput.h:
    (JSC::FTL::Output::allocaName):  Added. Useful for debugging.
    * ftl/FTLState.cpp:
    (JSC::FTL::State::State): Added an include for InlineRuntimeSymbolTable.h
    * ftl/FTLState.h: Added symbol table hash table.
    * ftl/FTLCompile.cpp:
    (JSC::FTL::compile): Added inlining and dead function elimination passes.
    * heap/HandleStack.h: Added JS_EXPORT_PRIVATE to a few functions to get inlining to compile.
    * InlineRuntimeSymbolTable.h: Added.
    * llvm/InitializeLLVMMac.mm: Deleted.
    * llvm/InitializeLLVMMac.cpp: Added.
    * llvm/LLVMAPIFunctions.h: Added macros to include Bitcode parsing and linking functions.
    * llvm/LLVMHeaders.h: Added includes for Bitcode parsing and linking.
    * runtime/BundlePath.h: Added.
    * runtime/BundlePath.mm: Added.
    * runtime/DateInstance.h: Added JS_EXPORT_PRIVATE to a few functions to get inlining to compile.
    * runtime/DateInstance.h: ditto.
    * runtime/DateConversion.h: ditto.
    * runtime/ExceptionHelpers.h: ditto.
    * runtime/JSCJSValue.h: ditto.
    * runtime/JSArray.h: ditto.
    * runtime/JSDateMath.h: ditto.
    * runtime/JSObject.h: ditto.
    * runtime/JSObject.h: ditto.
    * runtime/RegExp.h: ditto.
    * runtime/Structure.h: ditto.
    * runtime/Options.h:  Added maximumLLVMInstructionCountForNativeInlining.
    * tests/stress/ftl-library-inlining-random.js: Added.
    * tests/stress/ftl-library-substring.js: Added.

    2014-05-21  Filip Pizlo  <fpizlo@apple.com>

    [ftlopt] DFG::clobberize should be blind to the effects of GC
    https://bugs.webkit.org/show_bug.cgi?id=133166

    Reviewed by Goeffrey Garen.

    Move the computation of where GCs happen to DFG::doesGC().

    Large (>5x) speed-up on programs that do loop-invariant string concatenations.

    * CMakeLists.txt:
    * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
    * JavaScriptCore.xcodeproj/project.pbxproj:
    * dfg/DFGAbstractHeap.h:
    * dfg/DFGClobberize.h:
    (JSC::DFG::clobberize):
    (JSC::DFG::clobberizeForAllocation): Deleted.
    * dfg/DFGDoesGC.cpp: Added.
    (JSC::DFG::doesGC):
    * dfg/DFGDoesGC.h: Added.
    * dfg/DFGStoreBarrierElisionPhase.cpp:
    (JSC::DFG::StoreBarrierElisionPhase::handleNode):
    (JSC::DFG::StoreBarrierElisionPhase::couldCauseGC): Deleted.

    2014-05-16  Filip Pizlo  <fpizlo@apple.com>

    [ftlopt] A StructureSet with one element should only require one word and no allocation
    https://bugs.webkit.org/show_bug.cgi?id=133014

    Reviewed by Oliver Hunt.

    This makes it more efficient to use StructureSet in situations where the common case is
    just one structure.

    I also took the opportunity to use the same set terminology we use in BitVector: merge,
    filter, exclude, contains, etc.

    Eventually, this will be used to implement StructureAbstractValue as well.

    * CMakeLists.txt:
    * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
    * JavaScriptCore.xcodeproj/project.pbxproj:
    * bytecode/StructureSet.cpp: Added.
    (JSC::StructureSet::StructureSet):
    (JSC::StructureSet::operator=):
    (JSC::StructureSet::clear):
    (JSC::StructureSet::add):
    (JSC::StructureSet::remove):
    (JSC::StructureSet::contains):
    (JSC::StructureSet::merge):
    (JSC::StructureSet::filter):
    (JSC::StructureSet::exclude):
    (JSC::StructureSet::isSubsetOf):
    (JSC::StructureSet::overlaps):
    (JSC::StructureSet::operator==):
    (JSC::StructureSet::speculationFromStructures):
    (JSC::StructureSet::arrayModesFromStructures):
    (JSC::StructureSet::dumpInContext):
    (JSC::StructureSet::dump):
    (JSC::StructureSet::addOutOfLine):
    (JSC::StructureSet::containsOutOfLine):
    (JSC::StructureSet::copyFrom):
    (JSC::StructureSet::OutOfLineList::create):
    (JSC::StructureSet::OutOfLineList::destroy):
    * bytecode/StructureSet.h:
    (JSC::StructureSet::StructureSet):
    (JSC::StructureSet::~StructureSet):
    (JSC::StructureSet::onlyStructure):
    (JSC::StructureSet::isEmpty):
    (JSC::StructureSet::size):
    (JSC::StructureSet::at):
    (JSC::StructureSet::operator[]):
    (JSC::StructureSet::last):
    (JSC::StructureSet::OutOfLineList::list):
    (JSC::StructureSet::OutOfLineList::OutOfLineList):
    (JSC::StructureSet::deleteStructureListIfNecessary):
    (JSC::StructureSet::isThin):
    (JSC::StructureSet::pointer):
    (JSC::StructureSet::singleStructure):
    (JSC::StructureSet::structureList):
    (JSC::StructureSet::set):
    (JSC::StructureSet::clear): Deleted.
    (JSC::StructureSet::add): Deleted.
    (JSC::StructureSet::addAll): Deleted.
    (JSC::StructureSet::remove): Deleted.
    (JSC::StructureSet::contains): Deleted.
    (JSC::StructureSet::containsOnly): Deleted.
    (JSC::StructureSet::isSubsetOf): Deleted.
    (JSC::StructureSet::overlaps): Deleted.
    (JSC::StructureSet::singletonStructure): Deleted.
    (JSC::StructureSet::speculationFromStructures): Deleted.
    (JSC::StructureSet::arrayModesFromStructures): Deleted.
    (JSC::StructureSet::operator==): Deleted.
    (JSC::StructureSet::dumpInContext): Deleted.
    (JSC::StructureSet::dump): Deleted.
    * dfg/DFGAbstractInterpreterInlines.h:
    (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
    * dfg/DFGByteCodeParser.cpp:
    (JSC::DFG::ByteCodeParser::emitPrototypeChecks):
    (JSC::DFG::ByteCodeParser::handleGetById):
    (JSC::DFG::ByteCodeParser::parseBlock):
    * dfg/DFGCSEPhase.cpp:
    (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
    * dfg/DFGNode.h:
    (JSC::DFG::Node::convertToStructureTransitionWatchpoint):
    * dfg/DFGTypeCheckHoistingPhase.cpp:
    (JSC::DFG::TypeCheckHoistingPhase::noticeStructureCheck):

Source/WTF:

    2014-06-04  Filip Pizlo  <fpizlo@apple.com>

    [ftlopt] AI should be able track structure sets larger than 1
    https://bugs.webkit.org/show_bug.cgi?id=128073

    Reviewed by Oliver Hunt.

    * wtf/Bag.h:
    (WTF::Bag::Node::Node):
    (WTF::Bag::add):

LayoutTests:

    2014-06-04  Filip Pizlo  <fpizlo@apple.com>

    [ftlopt] AI should be able track structure sets larger than 1
    https://bugs.webkit.org/show_bug.cgi?id=128073

    Reviewed by Oliver Hunt.

    * js/regress/get-by-id-bimorphic-check-structure-elimination-expected.txt: Added.
    * js/regress/get-by-id-bimorphic-check-structure-elimination-simple-expected.txt: Added.
    * js/regress/get-by-id-bimorphic-check-structure-elimination-simple.html: Added.
    * js/regress/get-by-id-bimorphic-check-structure-elimination.html: Added.
    * js/regress/get-by-id-check-structure-elimination-expected.txt: Added.
    * js/regress/get-by-id-check-structure-elimination.html: Added.
    * js/regress/get-by-id-quadmorphic-check-structure-elimination-simple-expected.txt: Added.
    * js/regress/get-by-id-quadmorphic-check-structure-elimination-simple.html: Added.
    * js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination-simple.js: Added.
    * js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination.js: Added.
    * js/regress/script-tests/get-by-id-check-structure-elimination.js: Added.
    * js/regress/script-tests/get-by-id-quadmorphic-check-structure-elimination-simple.js: Added.

    2014-06-03  Filip Pizlo  <fpizlo@apple.com>

    [ftlopt] FTL native inlining tests take far too long
    https://bugs.webkit.org/show_bug.cgi?id=133498

    Unreviewed test gardening.

    Move long-running tests that focus on correctness into JSC/tests/stress.
    Speed up the performance tests by reducing allocation and call overhead.

    * js/regress/ftl-library-inlining-exceptions-expected.txt: Removed.
    * js/regress/ftl-library-inlining-exceptions.html: Removed.
    * js/regress/ftl-library-inlining-folding-expected.txt: Removed.
    * js/regress/ftl-library-inlining-folding.html: Removed.
    * js/regress/ftl-library-inlining-loops-expected.txt: Removed.
    * js/regress/ftl-library-inlining-loops.html: Removed.
    * js/regress/script-tests/ftl-library-inlining-dataview.js:
    (foo): Deleted.
    * js/regress/script-tests/ftl-library-inlining-exceptions.js: Removed.
    * js/regress/script-tests/ftl-library-inlining-folding.js: Removed.
    * js/regress/script-tests/ftl-library-inlining-loops.js: Removed.
    * js/regress/script-tests/ftl-library-inlining.js:
    (foo): Deleted.

    2014-06-03  Matthew Mirman  <mmirman@apple.com>

    [ftlopt] Added system for inlining native functions via the FTL.
    https://bugs.webkit.org/show_bug.cgi?id=131515

    Reviewed by Filip Pizlo.

    Adds microbenchmarks.

    * js/regress/script-tests/ftl-library-inlining.js: Added.
    * js/regress/ftl-library-inlining-expected.txt: Added.
    * js/regress/ftl-library-inlining.html: Added.
    * js/regress/script-tests/ftl-library-inlining-dataview.js: Added.
    * js/regress/ftl-library-inlining-dataview-expected.txt: Added.
    * js/regress/ftl-library-inlining-dataview.html: Added.
    * js/regress/script-tests/ftl-library-inlining-exceptions.js: Added.
    * js/regress/ftl-library-inlining-exceptions-expected.txt: Added.
    * js/regress/ftl-library-inlining-exceptions.html: Added.
    * js/regress/script-tests/ftl-library-inlining-folding.js: Added.
    * js/regress/ftl-library-inlining-folding-expected.txt: Added.
    * js/regress/ftl-library-inlining-folding-expected.html: Added.
    * js/regress/script-tests/ftl-library-inlining-loops.js: Added.
    * js/regress/ftl-library-inlining-loops-expected.txt: Added.
    * js/regress/ftl-library-inlining-loops.html: Added.

    2014-05-21  Filip Pizlo  <fpizlo@apple.com>

    [ftlopt] DFG::clobberize should be blind to the effects of GC
    https://bugs.webkit.org/show_bug.cgi?id=133166

    Reviewed by Geoffrey Garen.

    * js/regress/hoist-make-rope-expected.txt: Added.
    * js/regress/hoist-make-rope.html: Added.
    * js/regress/script-tests/hoist-make-rope.js: Added.
    (foo):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@171380 268f45cc-cd09-0410-ab3c-d52691b4dbfc

99 files changed:
LayoutTests/ChangeLog
LayoutTests/js/regress/ftl-library-inlining-dataview-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/ftl-library-inlining-dataview.html [new file with mode: 0644]
LayoutTests/js/regress/ftl-library-inlining-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/ftl-library-inlining.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-id-check-structure-elimination-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-id-check-structure-elimination.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple.html [new file with mode: 0644]
LayoutTests/js/regress/hoist-make-rope-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/hoist-make-rope.html [new file with mode: 0644]
LayoutTests/js/regress/script-tests/ftl-library-inlining-dataview.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/ftl-library-inlining.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination-simple.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-id-check-structure-elimination.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-id-quadmorphic-check-structure-elimination-simple.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/hoist-make-rope.js [new file with mode: 0644]
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/StructureSet.cpp [new file with mode: 0644]
Source/JavaScriptCore/bytecode/StructureSet.h
Source/JavaScriptCore/dfg/DFGAbstractHeap.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGAbstractValue.cpp
Source/JavaScriptCore/dfg/DFGAbstractValue.h
Source/JavaScriptCore/dfg/DFGAllocator.h
Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
Source/JavaScriptCore/dfg/DFGArrayMode.cpp
Source/JavaScriptCore/dfg/DFGAtTailAbstractState.h
Source/JavaScriptCore/dfg/DFGBasicBlock.cpp
Source/JavaScriptCore/dfg/DFGBasicBlock.h
Source/JavaScriptCore/dfg/DFGBranchDirection.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGCommon.cpp
Source/JavaScriptCore/dfg/DFGCommon.h
Source/JavaScriptCore/dfg/DFGCommonData.cpp
Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp
Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGDoesGC.h [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.h
Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPlan.cpp
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStoreBarrierElisionPhase.cpp
Source/JavaScriptCore/dfg/DFGStructureAbstractValue.cpp [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h
Source/JavaScriptCore/dfg/DFGStructureClobberState.h [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGTransition.cpp [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGTransition.h [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp
Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.h [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/ftl/FTLOutput.cpp
Source/JavaScriptCore/ftl/FTLOutput.h
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/runtime/Structure.h
Source/JavaScriptCore/tests/stress/arrayify-to-structure-contradiction.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/ftl-getmyargumentslength-inline.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/ftl-library-exception.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/ftl-library-inline-gettimezoneoffset.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/ftl-library-inlining-exceptions-dataview.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/ftl-library-inlining-exceptions.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/ftl-library-inlining-loops.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/ftl-library-inlining-random.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/ftl-library-substring.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multi-put-by-offset-multiple-transitions.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/throw-from-ftl-in-loop.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/throw-from-ftl.js [new file with mode: 0644]
Source/WTF/ChangeLog
Source/WTF/wtf/Bag.h

index 8cfffd1..f778bd0 100644 (file)
@@ -1,3 +1,88 @@
+2014-07-22  Filip Pizlo  <fpizlo@apple.com>
+
+        Merge r169148, r169185, r169188, r169578, r169582, r169584, r169588, r169753 from ftlopt.
+
+    2014-06-04  Filip Pizlo  <fpizlo@apple.com>
+    
+            [ftlopt] AI should be able track structure sets larger than 1
+            https://bugs.webkit.org/show_bug.cgi?id=128073
+    
+            Reviewed by Oliver Hunt.
+    
+            * js/regress/get-by-id-bimorphic-check-structure-elimination-expected.txt: Added.
+            * js/regress/get-by-id-bimorphic-check-structure-elimination-simple-expected.txt: Added.
+            * js/regress/get-by-id-bimorphic-check-structure-elimination-simple.html: Added.
+            * js/regress/get-by-id-bimorphic-check-structure-elimination.html: Added.
+            * js/regress/get-by-id-check-structure-elimination-expected.txt: Added.
+            * js/regress/get-by-id-check-structure-elimination.html: Added.
+            * js/regress/get-by-id-quadmorphic-check-structure-elimination-simple-expected.txt: Added.
+            * js/regress/get-by-id-quadmorphic-check-structure-elimination-simple.html: Added.
+            * js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination-simple.js: Added.
+            * js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination.js: Added.
+            * js/regress/script-tests/get-by-id-check-structure-elimination.js: Added.
+            * js/regress/script-tests/get-by-id-quadmorphic-check-structure-elimination-simple.js: Added.
+    
+    2014-06-03  Filip Pizlo  <fpizlo@apple.com>
+    
+            [ftlopt] FTL native inlining tests take far too long
+            https://bugs.webkit.org/show_bug.cgi?id=133498
+    
+            Unreviewed test gardening.
+            
+            Move long-running tests that focus on correctness into JSC/tests/stress.
+            Speed up the performance tests by reducing allocation and call overhead.
+    
+            * js/regress/ftl-library-inlining-exceptions-expected.txt: Removed.
+            * js/regress/ftl-library-inlining-exceptions.html: Removed.
+            * js/regress/ftl-library-inlining-folding-expected.txt: Removed.
+            * js/regress/ftl-library-inlining-folding.html: Removed.
+            * js/regress/ftl-library-inlining-loops-expected.txt: Removed.
+            * js/regress/ftl-library-inlining-loops.html: Removed.
+            * js/regress/script-tests/ftl-library-inlining-dataview.js:
+            (foo): Deleted.
+            * js/regress/script-tests/ftl-library-inlining-exceptions.js: Removed.
+            * js/regress/script-tests/ftl-library-inlining-folding.js: Removed.
+            * js/regress/script-tests/ftl-library-inlining-loops.js: Removed.
+            * js/regress/script-tests/ftl-library-inlining.js:
+            (foo): Deleted.
+    
+    2014-06-03  Matthew Mirman  <mmirman@apple.com>
+    
+            [ftlopt] Added system for inlining native functions via the FTL.
+            https://bugs.webkit.org/show_bug.cgi?id=131515
+    
+            Reviewed by Filip Pizlo.
+    
+            Adds microbenchmarks. 
+    
+            * js/regress/script-tests/ftl-library-inlining.js: Added.
+            * js/regress/ftl-library-inlining-expected.txt: Added.
+            * js/regress/ftl-library-inlining.html: Added.
+            * js/regress/script-tests/ftl-library-inlining-dataview.js: Added.
+            * js/regress/ftl-library-inlining-dataview-expected.txt: Added.
+            * js/regress/ftl-library-inlining-dataview.html: Added.
+            * js/regress/script-tests/ftl-library-inlining-exceptions.js: Added.
+            * js/regress/ftl-library-inlining-exceptions-expected.txt: Added.        
+            * js/regress/ftl-library-inlining-exceptions.html: Added.                
+            * js/regress/script-tests/ftl-library-inlining-folding.js: Added.
+            * js/regress/ftl-library-inlining-folding-expected.txt: Added.        
+            * js/regress/ftl-library-inlining-folding-expected.html: Added.                
+            * js/regress/script-tests/ftl-library-inlining-loops.js: Added.
+            * js/regress/ftl-library-inlining-loops-expected.txt: Added.        
+            * js/regress/ftl-library-inlining-loops.html: Added.                
+            
+    2014-05-21  Filip Pizlo  <fpizlo@apple.com>
+    
+            [ftlopt] DFG::clobberize should be blind to the effects of GC
+            https://bugs.webkit.org/show_bug.cgi?id=133166
+    
+            Reviewed by Geoffrey Garen.
+    
+            * js/regress/hoist-make-rope-expected.txt: Added.
+            * js/regress/hoist-make-rope.html: Added.
+            * js/regress/script-tests/hoist-make-rope.js: Added.
+            (foo):
+    
 2014-07-22  Alex Christensen  <achristensen@webkit.org>
 
         Fix window-inactive css selectors when using querySelector.
diff --git a/LayoutTests/js/regress/ftl-library-inlining-dataview-expected.txt b/LayoutTests/js/regress/ftl-library-inlining-dataview-expected.txt
new file mode 100644 (file)
index 0000000..5c2a972
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/ftl-library-inlining-dataview
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/ftl-library-inlining-dataview.html b/LayoutTests/js/regress/ftl-library-inlining-dataview.html
new file mode 100644 (file)
index 0000000..628189d
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/ftl-library-inlining-dataview.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/ftl-library-inlining-expected.txt b/LayoutTests/js/regress/ftl-library-inlining-expected.txt
new file mode 100644 (file)
index 0000000..f04fdb3
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/ftl-library-inlining
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/ftl-library-inlining.html b/LayoutTests/js/regress/ftl-library-inlining.html
new file mode 100644 (file)
index 0000000..ffdaf2e
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/ftl-library-inlining.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-expected.txt b/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-expected.txt
new file mode 100644 (file)
index 0000000..09c5a7e
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-id-bimorphic-check-structure-elimination
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple-expected.txt b/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple-expected.txt
new file mode 100644 (file)
index 0000000..11c52c4
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-id-bimorphic-check-structure-elimination-simple
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple.html b/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple.html
new file mode 100644 (file)
index 0000000..859ad6b
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-id-bimorphic-check-structure-elimination-simple.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination.html b/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination.html
new file mode 100644 (file)
index 0000000..d9b61b0
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-id-bimorphic-check-structure-elimination.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-id-check-structure-elimination-expected.txt b/LayoutTests/js/regress/get-by-id-check-structure-elimination-expected.txt
new file mode 100644 (file)
index 0000000..1184ca9
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-id-check-structure-elimination
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-id-check-structure-elimination.html b/LayoutTests/js/regress/get-by-id-check-structure-elimination.html
new file mode 100644 (file)
index 0000000..8d56374
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-id-check-structure-elimination.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple-expected.txt b/LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple-expected.txt
new file mode 100644 (file)
index 0000000..bf12441
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-id-quadmorphic-check-structure-elimination-simple
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple.html b/LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple.html
new file mode 100644 (file)
index 0000000..08f5d77
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-id-quadmorphic-check-structure-elimination-simple.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/hoist-make-rope-expected.txt b/LayoutTests/js/regress/hoist-make-rope-expected.txt
new file mode 100644 (file)
index 0000000..e6bdd3f
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/hoist-make-rope
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/hoist-make-rope.html b/LayoutTests/js/regress/hoist-make-rope.html
new file mode 100644 (file)
index 0000000..6c3662d
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/hoist-make-rope.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/script-tests/ftl-library-inlining-dataview.js b/LayoutTests/js/regress/script-tests/ftl-library-inlining-dataview.js
new file mode 100644 (file)
index 0000000..12fbdf0
--- /dev/null
@@ -0,0 +1,13 @@
+(function() {
+    var result = 0;
+    var d = new DataView(new ArrayBuffer(5));
+    for (var i = 0; i < 1000000; i++) {
+        d.setInt8(0, 4);
+        d.setInt8(1, 2);
+        d.setInt8(2, 6);
+        d.setInt16(0, 20);
+        result += d.getInt8(2) + d.getInt8(0);
+    }
+    if (result != 6000000) 
+        throw "Bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/ftl-library-inlining.js b/LayoutTests/js/regress/script-tests/ftl-library-inlining.js
new file mode 100644 (file)
index 0000000..a107ae1
--- /dev/null
@@ -0,0 +1,4 @@
+(function() {
+    for (var i = 0 ; i < 10000000; i++)
+        Math.random();
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination-simple.js b/LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination-simple.js
new file mode 100644 (file)
index 0000000..2f136d4
--- /dev/null
@@ -0,0 +1,13 @@
+(function() {
+    var o = {a:1};
+    var p = {a:2, l:13};
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i) {
+        result ^= o.a;
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != 0)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination.js b/LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination.js
new file mode 100644 (file)
index 0000000..2c6bd87
--- /dev/null
@@ -0,0 +1,13 @@
+(function() {
+    var o = {a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11};
+    var p = {a:2, b:3, c:4, d:5, e:6, f:7, g:8, h:9, i:10, j:11, k:12, l:13};
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i) {
+        result += o.a ^ o.b ^ o.c ^ o.d ^ o.e ^ o.f ^ o.g ^ o.h ^ o.i ^ o.j ^ o.k;
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != 6500000)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-id-check-structure-elimination.js b/LayoutTests/js/regress/script-tests/get-by-id-check-structure-elimination.js
new file mode 100644 (file)
index 0000000..7e46546
--- /dev/null
@@ -0,0 +1,8 @@
+(function() {
+    var o = {a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11};
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i)
+        result += o.a ^ o.b | o.c ^ o.d & o.e ^ o.f | o.g ^ o.h & o.i ^ o.j | o.k;
+    if (result != 15000000)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-id-quadmorphic-check-structure-elimination-simple.js b/LayoutTests/js/regress/script-tests/get-by-id-quadmorphic-check-structure-elimination-simple.js
new file mode 100644 (file)
index 0000000..80ebfda
--- /dev/null
@@ -0,0 +1,17 @@
+(function() {
+    var o = {a:1};
+    var p = {a:2, l:13};
+    var q = {a:3, b:3};
+    var r = {a:4, c:5};
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i) {
+        result ^= o.a;
+        var tmp = o;
+        o = p;
+        p = q;
+        q = r;
+        r = tmp;
+    }
+    if (result != 0)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/hoist-make-rope.js b/LayoutTests/js/regress/script-tests/hoist-make-rope.js
new file mode 100644 (file)
index 0000000..4069615
--- /dev/null
@@ -0,0 +1,14 @@
+function foo(a, b) {
+    var result;
+    for (var i = 0; i < 10000; ++i)
+        result = a + b;
+    return result;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 500; ++i) {
+    var result = foo("hello ", "world!");
+    if (result != "hello world!")
+        throw "Error: bad result: " + result;
+}
index 2a76770..4c27459 100644 (file)
@@ -90,6 +90,7 @@ set(JavaScriptCore_SOURCES
     bytecode/SamplingTool.cpp
     bytecode/SpecialPointer.cpp
     bytecode/SpeculatedType.cpp
+    bytecode/StructureSet.cpp
     bytecode/StructureStubClearingWatchpoint.cpp
     bytecode/StructureStubInfo.cpp
     bytecode/UnlinkedCodeBlock.cpp
@@ -137,6 +138,7 @@ set(JavaScriptCore_SOURCES
     dfg/DFGDesiredWeakReferences.cpp
     dfg/DFGDesiredWriteBarriers.cpp
     dfg/DFGDisassembler.cpp
+    dfg/DFGDoesGC.cpp
     dfg/DFGDominators.cpp
     dfg/DFGDriver.cpp
     dfg/DFGEdge.cpp
@@ -191,9 +193,11 @@ set(JavaScriptCore_SOURCES
     dfg/DFGStaticExecutionCountEstimationPhase.cpp
     dfg/DFGStoreBarrierElisionPhase.cpp
     dfg/DFGStrengthReductionPhase.cpp
+    dfg/DFGStructureAbstractValue.cpp
     dfg/DFGThreadData.cpp
     dfg/DFGThunks.cpp
     dfg/DFGTierUpCheckInjectionPhase.cpp
+    dfg/DFGTransition.cpp
     dfg/DFGTypeCheckHoistingPhase.cpp
     dfg/DFGUnificationPhase.cpp
     dfg/DFGUseKind.cpp
@@ -204,6 +208,7 @@ set(JavaScriptCore_SOURCES
     dfg/DFGVariableEvent.cpp
     dfg/DFGVariableEventStream.cpp
     dfg/DFGVirtualRegisterAllocationPhase.cpp
+    dfg/DFGWatchableStructureWatchingPhase.cpp
     dfg/DFGWatchpointCollectionPhase.cpp
     dfg/DFGWorklist.cpp
 
index a520355..437fdac 100644 (file)
@@ -1,3 +1,662 @@
+2014-07-22  Filip Pizlo  <fpizlo@apple.com>
+
+        Merge r169148, r169185, r169188, r169578, r169582, r169584, r169588, r169753 from ftlopt.
+        
+        Note that r169753 is merged out of order because it fixes a bug in r169588.
+
+    2014-06-10  Filip Pizlo  <fpizlo@apple.com>
+    
+            [ftlopt] Structure::dfgShouldWatchIfPossible() is unsound
+            https://bugs.webkit.org/show_bug.cgi?id=133624
+    
+            Reviewed by Mark Hahnenberg.
+    
+            * runtime/Structure.h:
+            (JSC::Structure::dfgShouldWatchIfPossible): Make it sound and add some verbiage.
+    
+    2014-06-04  Filip Pizlo  <fpizlo@apple.com>
+    
+            [ftlopt] AI should be able track structure sets larger than 1
+            https://bugs.webkit.org/show_bug.cgi?id=128073
+    
+            Reviewed by Oliver Hunt.
+            
+            This makes two major changes to how AI (abstract interpreter) proves that a value has
+            some structure:
+            
+            - StructureAbstractValue can now track an arbitrary number of structures. A set whose
+              size is greater than one means that the value may have any of the structures, and we
+              don't know which - but we do know that it cannot be any structure not in the set. The
+              structure abstract value can still be TOP, which means the set of all structures. We
+              artificially limit the set size to StructureAbstractValue::polymorphismLimit to guard
+              memory explosion on pathological programs. This limit is big enough that it wouldn't
+              kick in for normal code, since we have other heuristics that limit the number of
+              structures that we would allow an inline cache to know about.
+            
+            - We eagerly set watchpoints on all watchable structures and then we assume that
+              watchable structures are being watched, and that the watchpoint will jettison the code.
+              This allows tracking of watchable structures to be far simpler than before. Previously,
+              a structure being tracked as "future possible" was predicated on it being watchable but
+              we might not actually watch it. This makes algebra over sets of future possible
+              structures quite weird. But watching all watchable structures means that we simple say
+              that a structure set can be in the following states: unclobbered, which means it's just
+              a set of structures and it doesn't matter what is watchable or what isn't because we've
+              proven that the value must have one of these structures right now; and clobbered, which
+              means that we have a set of structures, plus all possible structures temporarily, with
+              invalidation removing the "plus all possible structures". Clobbering a set means that
+              if any of its structures are unwatchable, the set just becomes TOP; but if all
+              structures in the set are watchable then we just set the clobbered bit to add the "plus
+              all possible structures temporarily" thing. This precisely tracks the exact meaning of
+              watchability and invalidation points.
+            
+            Slight SunSpider slow-down, neutral on Octane, slight AsmBench speed-up. I believe that
+            we will ultimately undo the SunSpider slow-down by making further improvements to the set
+            representation. I believe that Octane perfromance will ultimately improve once we remove
+            remaining singleton special-cases. The ultimate goal of this is to remove the need to
+            try quite so desperately hard to make everything monomorphic as we do currently.
+    
+            * CMakeLists.txt:
+            * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+            * JavaScriptCore.xcodeproj/project.pbxproj:
+            * bytecode/StructureSet.cpp:
+            (JSC::StructureSet::clear):
+            (JSC::StructureSet::remove):
+            (JSC::StructureSet::filter):
+            (JSC::StructureSet::copyFromOutOfLine):
+            (JSC::StructureSet::StructureSet): Deleted.
+            (JSC::StructureSet::operator=): Deleted.
+            (JSC::StructureSet::copyFrom): Deleted.
+            * bytecode/StructureSet.h:
+            (JSC::StructureSet::StructureSet):
+            (JSC::StructureSet::operator=):
+            (JSC::StructureSet::isEmpty):
+            (JSC::StructureSet::genericFilter):
+            (JSC::StructureSet::ContainsOutOfLine::ContainsOutOfLine):
+            (JSC::StructureSet::ContainsOutOfLine::operator()):
+            (JSC::StructureSet::copyFrom):
+            (JSC::StructureSet::deleteStructureListIfNecessary):
+            (JSC::StructureSet::setEmpty):
+            (JSC::StructureSet::getReservedFlag):
+            (JSC::StructureSet::setReservedFlag):
+            * dfg/DFGAbstractInterpreter.h:
+            (JSC::DFG::AbstractInterpreter::setBuiltInConstant):
+            * dfg/DFGAbstractInterpreterInlines.h:
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::booleanResult):
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::verifyEdge):
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::clobberCapturedVars):
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::forAllValues):
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::clobberStructures):
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransition):
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransitions):
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::setDidClobber):
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::dump):
+            * dfg/DFGAbstractValue.cpp:
+            (JSC::DFG::AbstractValue::observeTransitions):
+            (JSC::DFG::AbstractValue::setMostSpecific):
+            (JSC::DFG::AbstractValue::set):
+            (JSC::DFG::AbstractValue::filter):
+            (JSC::DFG::AbstractValue::shouldBeClear):
+            (JSC::DFG::AbstractValue::normalizeClarity):
+            (JSC::DFG::AbstractValue::checkConsistency):
+            (JSC::DFG::AbstractValue::assertIsWatched):
+            (JSC::DFG::AbstractValue::dumpInContext):
+            (JSC::DFG::AbstractValue::setFuturePossibleStructure): Deleted.
+            * dfg/DFGAbstractValue.h:
+            (JSC::DFG::AbstractValue::clear):
+            (JSC::DFG::AbstractValue::clobberStructures):
+            (JSC::DFG::AbstractValue::clobberStructuresFor):
+            (JSC::DFG::AbstractValue::observeInvalidationPoint):
+            (JSC::DFG::AbstractValue::observeInvalidationPointFor):
+            (JSC::DFG::AbstractValue::observeTransition):
+            (JSC::DFG::AbstractValue::TransitionObserver::TransitionObserver):
+            (JSC::DFG::AbstractValue::TransitionObserver::operator()):
+            (JSC::DFG::AbstractValue::TransitionsObserver::TransitionsObserver):
+            (JSC::DFG::AbstractValue::TransitionsObserver::operator()):
+            (JSC::DFG::AbstractValue::isHeapTop):
+            (JSC::DFG::AbstractValue::setType):
+            (JSC::DFG::AbstractValue::operator==):
+            (JSC::DFG::AbstractValue::merge):
+            (JSC::DFG::AbstractValue::validate):
+            (JSC::DFG::AbstractValue::hasClobberableState):
+            (JSC::DFG::AbstractValue::assertIsWatched):
+            (JSC::DFG::AbstractValue::observeIndexingTypeTransition):
+            (JSC::DFG::AbstractValue::makeTop):
+            (JSC::DFG::AbstractValue::bestProvenStructure): Deleted.
+            * dfg/DFGAllocator.h:
+            * dfg/DFGArgumentsSimplificationPhase.cpp:
+            (JSC::DFG::ArgumentsSimplificationPhase::run):
+            * dfg/DFGArrayMode.cpp:
+            (JSC::DFG::ArrayMode::alreadyChecked):
+            * dfg/DFGAtTailAbstractState.h:
+            (JSC::DFG::AtTailAbstractState::structureClobberState):
+            (JSC::DFG::AtTailAbstractState::setStructureClobberState):
+            (JSC::DFG::AtTailAbstractState::setFoundConstants):
+            (JSC::DFG::AtTailAbstractState::haveStructures): Deleted.
+            (JSC::DFG::AtTailAbstractState::setHaveStructures): Deleted.
+            * dfg/DFGBasicBlock.cpp:
+            (JSC::DFG::BasicBlock::BasicBlock):
+            * dfg/DFGBasicBlock.h:
+            * dfg/DFGBranchDirection.h:
+            (JSC::DFG::branchDirectionToString):
+            (WTF::printInternal):
+            * dfg/DFGByteCodeParser.cpp:
+            (JSC::DFG::ByteCodeParser::handlePutById):
+            * dfg/DFGCFAPhase.cpp:
+            (JSC::DFG::CFAPhase::performBlockCFA):
+            * dfg/DFGCSEPhase.cpp:
+            (JSC::DFG::CSEPhase::checkStructureElimination):
+            (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
+            (JSC::DFG::CSEPhase::performNodeCSE):
+            * dfg/DFGClobberize.h:
+            (JSC::DFG::clobberize):
+            * dfg/DFGCommon.cpp:
+            (JSC::DFG::startCrashing):
+            (JSC::DFG::isCrashing):
+            * dfg/DFGCommon.h:
+            * dfg/DFGCommonData.cpp:
+            (JSC::DFG::CommonData::notifyCompilingStructureTransition):
+            * dfg/DFGConstantFoldingPhase.cpp:
+            (JSC::DFG::ConstantFoldingPhase::foldConstants):
+            (JSC::DFG::ConstantFoldingPhase::emitGetByOffset):
+            (JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
+            (JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck):
+            * dfg/DFGDesiredWatchpoints.cpp:
+            (JSC::DFG::DesiredWatchpoints::consider):
+            (JSC::DFG::DesiredWatchpoints::addLazily): Deleted.
+            * dfg/DFGDesiredWatchpoints.h:
+            (JSC::DFG::GenericDesiredWatchpoints::reallyAdd):
+            (JSC::DFG::GenericDesiredWatchpoints::areStillValid):
+            (JSC::DFG::GenericDesiredWatchpoints::isWatched):
+            (JSC::DFG::DesiredWatchpoints::isWatched):
+            (JSC::DFG::WatchpointForGenericWatchpointSet::WatchpointForGenericWatchpointSet): Deleted.
+            (JSC::DFG::GenericDesiredWatchpoints::addLazily): Deleted.
+            (JSC::DFG::GenericDesiredWatchpoints::isStillValid): Deleted.
+            (JSC::DFG::GenericDesiredWatchpoints::shouldAssumeMixedState): Deleted.
+            (JSC::DFG::GenericDesiredWatchpoints::isValidOrMixed): Deleted.
+            (JSC::DFG::DesiredWatchpoints::isStillValid): Deleted.
+            (JSC::DFG::DesiredWatchpoints::shouldAssumeMixedState): Deleted.
+            (JSC::DFG::DesiredWatchpoints::isValidOrMixed): Deleted.
+            * dfg/DFGDoesGC.cpp:
+            (JSC::DFG::doesGC):
+            * dfg/DFGFixupPhase.cpp:
+            (JSC::DFG::FixupPhase::fixupNode):
+            (JSC::DFG::FixupPhase::canOptimizeStringObjectAccess):
+            (JSC::DFG::FixupPhase::injectTypeConversionsForEdge):
+            * dfg/DFGGraph.cpp:
+            (JSC::DFG::Graph::~Graph):
+            (JSC::DFG::Graph::dump):
+            (JSC::DFG::Graph::dumpBlockHeader):
+            (JSC::DFG::Graph::tryGetFoldableView):
+            (JSC::DFG::Graph::visitChildren):
+            (JSC::DFG::Graph::assertIsWatched):
+            (JSC::DFG::Graph::handleAssertionFailure):
+            * dfg/DFGGraph.h:
+            (JSC::DFG::Graph::convertToConstant):
+            (JSC::DFG::Graph::masqueradesAsUndefinedWatchpointIsStillValid):
+            (JSC::DFG::Graph::addStructureTransitionData): Deleted.
+            * dfg/DFGInPlaceAbstractState.cpp:
+            (JSC::DFG::InPlaceAbstractState::beginBasicBlock):
+            (JSC::DFG::InPlaceAbstractState::initialize):
+            (JSC::DFG::InPlaceAbstractState::endBasicBlock):
+            (JSC::DFG::InPlaceAbstractState::reset):
+            (JSC::DFG::InPlaceAbstractState::merge):
+            * dfg/DFGInPlaceAbstractState.h:
+            (JSC::DFG::InPlaceAbstractState::structureClobberState):
+            (JSC::DFG::InPlaceAbstractState::setStructureClobberState):
+            (JSC::DFG::InPlaceAbstractState::setFoundConstants):
+            (JSC::DFG::InPlaceAbstractState::haveStructures): Deleted.
+            (JSC::DFG::InPlaceAbstractState::setHaveStructures): Deleted.
+            * dfg/DFGLivenessAnalysisPhase.cpp:
+            (JSC::DFG::LivenessAnalysisPhase::run):
+            * dfg/DFGNode.h:
+            (JSC::DFG::Node::hasTransition):
+            (JSC::DFG::Node::transition):
+            (JSC::DFG::Node::hasStructure):
+            (JSC::DFG::StructureTransitionData::StructureTransitionData): Deleted.
+            (JSC::DFG::Node::convertToStructureTransitionWatchpoint): Deleted.
+            (JSC::DFG::Node::hasStructureTransitionData): Deleted.
+            (JSC::DFG::Node::structureTransitionData): Deleted.
+            * dfg/DFGNodeType.h:
+            * dfg/DFGPlan.cpp:
+            (JSC::DFG::Plan::compileInThreadImpl):
+            * dfg/DFGPredictionPropagationPhase.cpp:
+            (JSC::DFG::PredictionPropagationPhase::propagate):
+            * dfg/DFGSafeToExecute.h:
+            (JSC::DFG::safeToExecute):
+            * dfg/DFGSpeculativeJIT.cpp:
+            (JSC::DFG::SpeculativeJIT::compileAllocatePropertyStorage):
+            (JSC::DFG::SpeculativeJIT::compileReallocatePropertyStorage):
+            * dfg/DFGSpeculativeJIT.h:
+            (JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure):
+            * dfg/DFGSpeculativeJIT32_64.cpp:
+            (JSC::DFG::SpeculativeJIT::compile):
+            * dfg/DFGSpeculativeJIT64.cpp:
+            (JSC::DFG::SpeculativeJIT::compile):
+            * dfg/DFGStructureAbstractValue.cpp: Added.
+            (JSC::DFG::StructureAbstractValue::assertIsWatched):
+            (JSC::DFG::StructureAbstractValue::clobber):
+            (JSC::DFG::StructureAbstractValue::observeTransition):
+            (JSC::DFG::StructureAbstractValue::observeTransitions):
+            (JSC::DFG::StructureAbstractValue::add):
+            (JSC::DFG::StructureAbstractValue::merge):
+            (JSC::DFG::StructureAbstractValue::mergeSlow):
+            (JSC::DFG::StructureAbstractValue::mergeNotTop):
+            (JSC::DFG::StructureAbstractValue::filter):
+            (JSC::DFG::StructureAbstractValue::filterSlow):
+            (JSC::DFG::StructureAbstractValue::contains):
+            (JSC::DFG::StructureAbstractValue::isSubsetOf):
+            (JSC::DFG::StructureAbstractValue::isSupersetOf):
+            (JSC::DFG::StructureAbstractValue::overlaps):
+            (JSC::DFG::StructureAbstractValue::equalsSlow):
+            (JSC::DFG::StructureAbstractValue::dumpInContext):
+            (JSC::DFG::StructureAbstractValue::dump):
+            * dfg/DFGStructureAbstractValue.h:
+            (JSC::DFG::StructureAbstractValue::StructureAbstractValue):
+            (JSC::DFG::StructureAbstractValue::operator=):
+            (JSC::DFG::StructureAbstractValue::clear):
+            (JSC::DFG::StructureAbstractValue::makeTop):
+            (JSC::DFG::StructureAbstractValue::assertIsWatched):
+            (JSC::DFG::StructureAbstractValue::observeInvalidationPoint):
+            (JSC::DFG::StructureAbstractValue::top):
+            (JSC::DFG::StructureAbstractValue::isClear):
+            (JSC::DFG::StructureAbstractValue::isTop):
+            (JSC::DFG::StructureAbstractValue::isNeitherClearNorTop):
+            (JSC::DFG::StructureAbstractValue::isClobbered):
+            (JSC::DFG::StructureAbstractValue::merge):
+            (JSC::DFG::StructureAbstractValue::filter):
+            (JSC::DFG::StructureAbstractValue::operator==):
+            (JSC::DFG::StructureAbstractValue::size):
+            (JSC::DFG::StructureAbstractValue::at):
+            (JSC::DFG::StructureAbstractValue::operator[]):
+            (JSC::DFG::StructureAbstractValue::onlyStructure):
+            (JSC::DFG::StructureAbstractValue::isSupersetOf):
+            (JSC::DFG::StructureAbstractValue::makeTopWhenThin):
+            (JSC::DFG::StructureAbstractValue::setClobbered):
+            (JSC::DFG::StructureAbstractValue::add): Deleted.
+            (JSC::DFG::StructureAbstractValue::addAll): Deleted.
+            (JSC::DFG::StructureAbstractValue::contains): Deleted.
+            (JSC::DFG::StructureAbstractValue::isSubsetOf): Deleted.
+            (JSC::DFG::StructureAbstractValue::doesNotContainAnyOtherThan): Deleted.
+            (JSC::DFG::StructureAbstractValue::isClearOrTop): Deleted.
+            (JSC::DFG::StructureAbstractValue::last): Deleted.
+            (JSC::DFG::StructureAbstractValue::speculationFromStructures): Deleted.
+            (JSC::DFG::StructureAbstractValue::isValidOffset): Deleted.
+            (JSC::DFG::StructureAbstractValue::hasSingleton): Deleted.
+            (JSC::DFG::StructureAbstractValue::singleton): Deleted.
+            (JSC::DFG::StructureAbstractValue::dumpInContext): Deleted.
+            (JSC::DFG::StructureAbstractValue::dump): Deleted.
+            (JSC::DFG::StructureAbstractValue::topValue): Deleted.
+            * dfg/DFGStructureClobberState.h: Added.
+            (JSC::DFG::merge):
+            (WTF::printInternal):
+            * dfg/DFGTransition.cpp: Added.
+            (JSC::DFG::Transition::dumpInContext):
+            (JSC::DFG::Transition::dump):
+            * dfg/DFGTransition.h: Added.
+            (JSC::DFG::Transition::Transition):
+            * dfg/DFGTypeCheckHoistingPhase.cpp:
+            (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
+            (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):
+            * dfg/DFGWatchableStructureWatchingPhase.cpp: Added.
+            (JSC::DFG::WatchableStructureWatchingPhase::WatchableStructureWatchingPhase):
+            (JSC::DFG::WatchableStructureWatchingPhase::run):
+            (JSC::DFG::WatchableStructureWatchingPhase::tryWatch):
+            (JSC::DFG::performWatchableStructureWatching):
+            * dfg/DFGWatchableStructureWatchingPhase.h: Added.
+            * dfg/DFGWatchpointCollectionPhase.cpp:
+            (JSC::DFG::WatchpointCollectionPhase::handle):
+            (JSC::DFG::WatchpointCollectionPhase::handleEdge): Deleted.
+            * ftl/FTLCapabilities.cpp:
+            (JSC::FTL::canCompile):
+            * ftl/FTLIntrinsicRepository.h:
+            * ftl/FTLLowerDFGToLLVM.cpp:
+            (JSC::FTL::ftlUnreachable):
+            (JSC::FTL::LowerDFGToLLVM::createPhiVariables):
+            (JSC::FTL::LowerDFGToLLVM::compileBlock):
+            (JSC::FTL::LowerDFGToLLVM::compileNode):
+            (JSC::FTL::LowerDFGToLLVM::compileUpsilon):
+            (JSC::FTL::LowerDFGToLLVM::compilePhi):
+            (JSC::FTL::LowerDFGToLLVM::compileDoubleRep):
+            (JSC::FTL::LowerDFGToLLVM::compileValueRep):
+            (JSC::FTL::LowerDFGToLLVM::compileValueToInt32):
+            (JSC::FTL::LowerDFGToLLVM::compileGetArgument):
+            (JSC::FTL::LowerDFGToLLVM::compileGetLocal):
+            (JSC::FTL::LowerDFGToLLVM::compileSetLocal):
+            (JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub):
+            (JSC::FTL::LowerDFGToLLVM::compileArithMul):
+            (JSC::FTL::LowerDFGToLLVM::compileArithDiv):
+            (JSC::FTL::LowerDFGToLLVM::compileArithMod):
+            (JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax):
+            (JSC::FTL::LowerDFGToLLVM::compileArithAbs):
+            (JSC::FTL::LowerDFGToLLVM::compileArithNegate):
+            (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure):
+            (JSC::FTL::LowerDFGToLLVM::compilePutStructure):
+            (JSC::FTL::LowerDFGToLLVM::compileGetById):
+            (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentsLength):
+            (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal):
+            (JSC::FTL::LowerDFGToLLVM::compileGetArrayLength):
+            (JSC::FTL::LowerDFGToLLVM::compileGetByVal):
+            (JSC::FTL::LowerDFGToLLVM::compilePutByVal):
+            (JSC::FTL::LowerDFGToLLVM::compileArrayPush):
+            (JSC::FTL::LowerDFGToLLVM::compileArrayPop):
+            (JSC::FTL::LowerDFGToLLVM::compileNewArray):
+            (JSC::FTL::LowerDFGToLLVM::compileNewArrayBuffer):
+            (JSC::FTL::LowerDFGToLLVM::compileAllocatePropertyStorage):
+            (JSC::FTL::LowerDFGToLLVM::compileReallocatePropertyStorage):
+            (JSC::FTL::LowerDFGToLLVM::compileToString):
+            (JSC::FTL::LowerDFGToLLVM::compileMakeRope):
+            (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
+            (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset):
+            (JSC::FTL::LowerDFGToLLVM::compileCompareEq):
+            (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
+            (JSC::FTL::LowerDFGToLLVM::compileSwitch):
+            (JSC::FTL::LowerDFGToLLVM::compare):
+            (JSC::FTL::LowerDFGToLLVM::boolify):
+            (JSC::FTL::LowerDFGToLLVM::terminate):
+            (JSC::FTL::LowerDFGToLLVM::lowInt32):
+            (JSC::FTL::LowerDFGToLLVM::lowInt52):
+            (JSC::FTL::LowerDFGToLLVM::opposite):
+            (JSC::FTL::LowerDFGToLLVM::lowCell):
+            (JSC::FTL::LowerDFGToLLVM::lowBoolean):
+            (JSC::FTL::LowerDFGToLLVM::lowDouble):
+            (JSC::FTL::LowerDFGToLLVM::lowJSValue):
+            (JSC::FTL::LowerDFGToLLVM::speculate):
+            (JSC::FTL::LowerDFGToLLVM::isArrayType):
+            (JSC::FTL::LowerDFGToLLVM::speculateStringObjectForStructureID):
+            (JSC::FTL::LowerDFGToLLVM::callCheck):
+            (JSC::FTL::LowerDFGToLLVM::buildExitArguments):
+            (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
+            (JSC::FTL::LowerDFGToLLVM::setInt52):
+            (JSC::FTL::LowerDFGToLLVM::crash):
+            (JSC::FTL::LowerDFGToLLVM::compileStructureTransitionWatchpoint): Deleted.
+            * ftl/FTLOutput.cpp:
+            (JSC::FTL::Output::crashNonTerminal): Deleted.
+            * ftl/FTLOutput.h:
+            (JSC::FTL::Output::crash): Deleted.
+            * jit/JITOperations.h:
+            * jsc.cpp:
+            (WTF::jscExit):
+            (functionQuit):
+            (main):
+            (printUsageStatement):
+            (CommandLine::parseArguments):
+            * runtime/Structure.h:
+            (JSC::Structure::dfgShouldWatchIfPossible):
+            (JSC::Structure::dfgShouldWatch):
+            * tests/stress/arrayify-to-structure-contradiction.js: Added.
+            (foo):
+            * tests/stress/ftl-getmyargumentslength-inline.js: Added.
+            (foo):
+            * tests/stress/multi-put-by-offset-multiple-transitions.js: Added.
+            (foo):
+            (Foo):
+            * tests/stress/throw-from-ftl-in-loop.js: Added.
+            * tests/stress/throw-from-ftl.js: Added.
+            (foo):
+    
+    2014-06-03  Filip Pizlo  <fpizlo@apple.com>
+    
+            [ftlopt] Unreviewed, roll out r169578. The build system needs some more love.
+    
+            * InlineRuntimeSymbolTable.h: Removed.
+            * JavaScriptCore.xcodeproj/project.pbxproj:
+            * build-symbol-table-index.py:
+            * build-symbol-table-index.sh:
+            * copy-llvm-ir-to-derived-sources.sh:
+            * dfg/DFGByteCodeParser.cpp:
+            (JSC::DFG::ByteCodeParser::handleCall):
+            * dfg/DFGNode.h:
+            (JSC::DFG::Node::canBeKnownFunction): Deleted.
+            (JSC::DFG::Node::hasKnownFunction): Deleted.
+            (JSC::DFG::Node::knownFunction): Deleted.
+            (JSC::DFG::Node::giveKnownFunction): Deleted.
+            * ftl/FTLAbbreviatedTypes.h:
+            * ftl/FTLCompile.cpp:
+            (JSC::FTL::compile):
+            * ftl/FTLLowerDFGToLLVM.cpp:
+            (JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
+            (JSC::FTL::LowerDFGToLLVM::lower):
+            (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct):
+            (JSC::FTL::LowerDFGToLLVM::possiblyCompileInlineableNativeCall): Deleted.
+            (JSC::FTL::LowerDFGToLLVM::getFunctionBySymbol): Deleted.
+            (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): Deleted.
+            (JSC::FTL::LowerDFGToLLVM::isInlinableSize): Deleted.
+            * ftl/FTLState.cpp:
+            (JSC::FTL::State::State):
+            * ftl/FTLState.h:
+            * heap/HandleStack.h:
+            * llvm/InitializeLLVM.h:
+            * llvm/InitializeLLVMMac.cpp: Removed.
+            * llvm/InitializeLLVMMac.mm: Added.
+            (JSC::initializeLLVMImpl):
+            * llvm/LLVMAPIFunctions.h:
+            * llvm/LLVMHeaders.h:
+            * runtime/BundlePath.h: Removed.
+            * runtime/BundlePath.mm: Removed.
+            * runtime/DateConversion.h:
+            * runtime/DateInstance.h:
+            * runtime/ExceptionHelpers.h:
+            * runtime/JSArray.h:
+            * runtime/JSCJSValue.h:
+            (JSC::JSValue::toFloat):
+            * runtime/JSDateMath.h:
+            * runtime/JSObject.h:
+            * runtime/JSWrapperObject.h:
+            * runtime/Options.h:
+            * runtime/RegExp.h:
+            * runtime/StringObject.h:
+            * runtime/Structure.h:
+            * tested-symbols.symlst: Removed.
+    
+    2014-06-03  Filip Pizlo  <fpizlo@apple.com>
+    
+            [ftlopt] FTL native inlining tests take far too long
+            https://bugs.webkit.org/show_bug.cgi?id=133498
+    
+            Unreviewed test gardening.
+            
+            Added a new exceptions test since the other one appears to not work.
+    
+            * tests/stress/ftl-library-exception.js:
+            * tests/stress/ftl-library-inline-gettimezoneoffset.js: Added.
+            (foo):
+            * tests/stress/ftl-library-inlining-exceptions-dataview.js: Added.
+            (foo):
+            * tests/stress/ftl-library-inlining-exceptions.js: Copied from LayoutTests/js/regress/script-tests/ftl-library-inlining-exceptions.js.
+            * tests/stress/ftl-library-inlining-loops.js: Copied from LayoutTests/js/regress/script-tests/ftl-library-inlining-loops.js.
+            * tests/stress/ftl-library-inlining-random.js:
+            * tests/stress/ftl-library-substring.js:
+    
+    2014-06-03  Matthew Mirman  <mmirman@apple.com>
+    
+            [ftlopt] Added system for inlining native functions via the FTL.
+            https://bugs.webkit.org/show_bug.cgi?id=131515
+    
+            Reviewed by Filip Pizlo.
+    
+            Also fixed the build to not compress the bitcode and to 
+            include all of the relevant runtime. With GCC_GENERATE_DEBUGGING_SYMBOLS = NO, 
+            the produced bitcode files are a 100th the size they were before.  
+            Now we can include all of the relevant runtime files with only a 3mb overhead. 
+            This is the same overhead as for two compressed files before, 
+            but done more efficiently (on both ends) and with less code.
+            
+            Deciding whether to inline native functions is left up to LLVM. 
+            The entire module containing the function is linked into the current 
+            compiled JS so that inlining the native functions shouldn't make them smaller.
+            
+            Rather than loading Runtime.symtbl at runtime FTLState.cpp now includes a file 
+            InlineRuntimeSymbolTable.h which statically builds the symbol table hash table.  
+            Currently build-symbol-table-index.py updates this file from the 
+            contents of tested-symbols.symlst when done building as a matter of convenience.  
+            However, in order to include the new contents of the file in the build
+            you'd need to build twice.  This will be fixed in future versions.
+    
+            * JavaScriptCore.xcodeproj/project.pbxproj: Added back runtime files to compile.
+            * build-symbol-table-index.py: Changed bitcode suffix. 
+            Added inclusion of only tested symbols.  
+            Added output to InlineRuntimeSymbolTable.h. 
+            * build-symbol-table-index.sh: Changed bitcode suffix.
+            * copy-llvm-ir-to-derived-sources.sh: Removed gzip compression.
+            * tested-symbols.symlst: Added.
+            * dfg/DFGByteCodeParser.cpp:
+            (JSC::DFG::ByteCodeParser::handleCall):  
+            Now sets the knownFunction of the call node if such a function exists 
+            and emits a check that during runtime the callee is in fact known.
+            * dfg/DFGNode.h:
+            Added functions to set the known function of a call node.
+            (JSC::DFG::Node::canBeKnownFunction): Added.
+            (JSC::DFG::Node::hasKnownFunction): Added.
+            (JSC::DFG::Node::knownFunction): Added.
+            (JSC::DFG::Node::giveKnownFunction): Added.
+            * ftl/FTLAbbreviatedTypes.h: Added a typedef for LLVMMemoryBufferRef
+            * ftl/FTLLowerDFGToLLVM.cpp:
+            (JSC::FTL::LowerDFGToLLVM::isInlinableSize): Added. Hardcoded threshold to 275.
+            (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): Added.
+            (JSC::FTL::LowerDFGToLLVM::getFunctionBySymbol): Added.
+            (JSC::FTL::LowerDFGToLLVM::possiblyCompileInlineableNativeCall): Added.
+            (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct):  
+            Added call to possiblyCompileInlineableNativeCall
+            * ftl/FTLOutput.h:
+            (JSC::FTL::Output::allocaName):  Added. Useful for debugging.
+            * ftl/FTLState.cpp:
+            (JSC::FTL::State::State): Added an include for InlineRuntimeSymbolTable.h
+            * ftl/FTLState.h: Added symbol table hash table.
+            * ftl/FTLCompile.cpp:
+            (JSC::FTL::compile): Added inlining and dead function elimination passes.
+            * heap/HandleStack.h: Added JS_EXPORT_PRIVATE to a few functions to get inlining to compile.
+            * InlineRuntimeSymbolTable.h: Added.  
+            * llvm/InitializeLLVMMac.mm: Deleted.
+            * llvm/InitializeLLVMMac.cpp: Added.
+            * llvm/LLVMAPIFunctions.h: Added macros to include Bitcode parsing and linking functions.
+            * llvm/LLVMHeaders.h: Added includes for Bitcode parsing and linking.
+            * runtime/BundlePath.h: Added.
+            * runtime/BundlePath.mm: Added.
+            * runtime/DateInstance.h: Added JS_EXPORT_PRIVATE to a few functions to get inlining to compile.
+            * runtime/DateInstance.h: ditto.
+            * runtime/DateConversion.h: ditto.
+            * runtime/ExceptionHelpers.h: ditto.
+            * runtime/JSCJSValue.h: ditto.
+            * runtime/JSArray.h: ditto.
+            * runtime/JSDateMath.h: ditto.
+            * runtime/JSObject.h: ditto.
+            * runtime/JSObject.h: ditto.
+            * runtime/RegExp.h: ditto.
+            * runtime/Structure.h: ditto.
+            * runtime/Options.h:  Added maximumLLVMInstructionCountForNativeInlining.
+            * tests/stress/ftl-library-inlining-random.js: Added.
+            * tests/stress/ftl-library-substring.js: Added.
+    
+    2014-05-21  Filip Pizlo  <fpizlo@apple.com>
+    
+            [ftlopt] DFG::clobberize should be blind to the effects of GC
+            https://bugs.webkit.org/show_bug.cgi?id=133166
+    
+            Reviewed by Goeffrey Garen.
+            
+            Move the computation of where GCs happen to DFG::doesGC().
+            
+            Large (>5x) speed-up on programs that do loop-invariant string concatenations.
+    
+            * CMakeLists.txt:
+            * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+            * JavaScriptCore.xcodeproj/project.pbxproj:
+            * dfg/DFGAbstractHeap.h:
+            * dfg/DFGClobberize.h:
+            (JSC::DFG::clobberize):
+            (JSC::DFG::clobberizeForAllocation): Deleted.
+            * dfg/DFGDoesGC.cpp: Added.
+            (JSC::DFG::doesGC):
+            * dfg/DFGDoesGC.h: Added.
+            * dfg/DFGStoreBarrierElisionPhase.cpp:
+            (JSC::DFG::StoreBarrierElisionPhase::handleNode):
+            (JSC::DFG::StoreBarrierElisionPhase::couldCauseGC): Deleted.
+    
+    2014-05-16  Filip Pizlo  <fpizlo@apple.com>
+    
+            [ftlopt] A StructureSet with one element should only require one word and no allocation
+            https://bugs.webkit.org/show_bug.cgi?id=133014
+    
+            Reviewed by Oliver Hunt.
+            
+            This makes it more efficient to use StructureSet in situations where the common case is
+            just one structure.
+            
+            I also took the opportunity to use the same set terminology we use in BitVector: merge,
+            filter, exclude, contains, etc.
+            
+            Eventually, this will be used to implement StructureAbstractValue as well.
+    
+            * CMakeLists.txt:
+            * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+            * JavaScriptCore.xcodeproj/project.pbxproj:
+            * bytecode/StructureSet.cpp: Added.
+            (JSC::StructureSet::StructureSet):
+            (JSC::StructureSet::operator=):
+            (JSC::StructureSet::clear):
+            (JSC::StructureSet::add):
+            (JSC::StructureSet::remove):
+            (JSC::StructureSet::contains):
+            (JSC::StructureSet::merge):
+            (JSC::StructureSet::filter):
+            (JSC::StructureSet::exclude):
+            (JSC::StructureSet::isSubsetOf):
+            (JSC::StructureSet::overlaps):
+            (JSC::StructureSet::operator==):
+            (JSC::StructureSet::speculationFromStructures):
+            (JSC::StructureSet::arrayModesFromStructures):
+            (JSC::StructureSet::dumpInContext):
+            (JSC::StructureSet::dump):
+            (JSC::StructureSet::addOutOfLine):
+            (JSC::StructureSet::containsOutOfLine):
+            (JSC::StructureSet::copyFrom):
+            (JSC::StructureSet::OutOfLineList::create):
+            (JSC::StructureSet::OutOfLineList::destroy):
+            * bytecode/StructureSet.h:
+            (JSC::StructureSet::StructureSet):
+            (JSC::StructureSet::~StructureSet):
+            (JSC::StructureSet::onlyStructure):
+            (JSC::StructureSet::isEmpty):
+            (JSC::StructureSet::size):
+            (JSC::StructureSet::at):
+            (JSC::StructureSet::operator[]):
+            (JSC::StructureSet::last):
+            (JSC::StructureSet::OutOfLineList::list):
+            (JSC::StructureSet::OutOfLineList::OutOfLineList):
+            (JSC::StructureSet::deleteStructureListIfNecessary):
+            (JSC::StructureSet::isThin):
+            (JSC::StructureSet::pointer):
+            (JSC::StructureSet::singleStructure):
+            (JSC::StructureSet::structureList):
+            (JSC::StructureSet::set):
+            (JSC::StructureSet::clear): Deleted.
+            (JSC::StructureSet::add): Deleted.
+            (JSC::StructureSet::addAll): Deleted.
+            (JSC::StructureSet::remove): Deleted.
+            (JSC::StructureSet::contains): Deleted.
+            (JSC::StructureSet::containsOnly): Deleted.
+            (JSC::StructureSet::isSubsetOf): Deleted.
+            (JSC::StructureSet::overlaps): Deleted.
+            (JSC::StructureSet::singletonStructure): Deleted.
+            (JSC::StructureSet::speculationFromStructures): Deleted.
+            (JSC::StructureSet::arrayModesFromStructures): Deleted.
+            (JSC::StructureSet::operator==): Deleted.
+            (JSC::StructureSet::dumpInContext): Deleted.
+            (JSC::StructureSet::dump): Deleted.
+            * dfg/DFGAbstractInterpreterInlines.h:
+            (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+            * dfg/DFGByteCodeParser.cpp:
+            (JSC::DFG::ByteCodeParser::emitPrototypeChecks):
+            (JSC::DFG::ByteCodeParser::handleGetById):
+            (JSC::DFG::ByteCodeParser::parseBlock):
+            * dfg/DFGCSEPhase.cpp:
+            (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
+            * dfg/DFGNode.h:
+            (JSC::DFG::Node::convertToStructureTransitionWatchpoint):
+            * dfg/DFGTypeCheckHoistingPhase.cpp:
+            (JSC::DFG::TypeCheckHoistingPhase::noticeStructureCheck):
+    
 2014-07-22  Ryuan Choi  <ryuan.choi@samsung.com>
 
         Unreviewed build fix attempt on the EFL port after r171362.
index 89fdaec..eac7baa 100644 (file)
     <ClCompile Include="..\bytecode\SamplingTool.cpp" />
     <ClCompile Include="..\bytecode\SpecialPointer.cpp" />
     <ClCompile Include="..\bytecode\SpeculatedType.cpp" />
+    <ClCompile Include="..\bytecode\StructureSet.cpp" />
     <ClCompile Include="..\bytecode\StructureStubClearingWatchpoint.cpp" />
     <ClCompile Include="..\bytecode\StructureStubInfo.cpp" />
     <ClCompile Include="..\bytecode\UnlinkedCodeBlock.cpp" />
     <ClCompile Include="..\dfg\DFGDesiredWeakReferences.cpp" />
     <ClCompile Include="..\dfg\DFGDesiredWriteBarriers.cpp" />
     <ClCompile Include="..\dfg\DFGDisassembler.cpp" />
+    <ClCompile Include="..\dfg\DFGDoesGC.cpp" />
     <ClCompile Include="..\dfg\DFGDominators.cpp" />
     <ClCompile Include="..\dfg\DFGDriver.cpp" />
     <ClCompile Include="..\dfg\DFGEdge.cpp" />
     <ClCompile Include="..\dfg\DFGStaticExecutionCountEstimationPhase.cpp" />
     <ClCompile Include="..\dfg\DFGStoreBarrierElisionPhase.cpp" />
     <ClCompile Include="..\dfg\DFGStrengthReductionPhase.cpp" />
+    <ClCompile Include="..\dfg\DFGStructureAbstractValue.cpp" />
     <ClCompile Include="..\dfg\DFGThreadData.cpp" />
     <ClCompile Include="..\dfg\DFGThunks.cpp" />
     <ClCompile Include="..\dfg\DFGTierUpCheckInjectionPhase.cpp" />
     <ClCompile Include="..\dfg\DFGToFTLDeferredCompilationCallback.cpp" />
     <ClCompile Include="..\dfg\DFGToFTLForOSREntryDeferredCompilationCallback.cpp" />
+    <ClCompile Include="..\dfg\DFGTransition.cpp" />
     <ClCompile Include="..\dfg\DFGTypeCheckHoistingPhase.cpp" />
     <ClCompile Include="..\dfg\DFGUnificationPhase.cpp" />
     <ClCompile Include="..\dfg\DFGUseKind.cpp" />
     <ClCompile Include="..\dfg\DFGVariableEventStream.cpp" />
     <ClCompile Include="..\dfg\DFGVirtualRegisterAllocationPhase.cpp" />
     <ClCompile Include="..\dfg\DFGWatchpointCollectionPhase.cpp" />
+    <ClCompile Include="..\dfg\DFGWatchableStructureWatchingPhase.cpp" />
     <ClCompile Include="..\dfg\DFGWorklist.cpp" />
     <ClCompile Include="..\disassembler\Disassembler.cpp" />
     <ClCompile Include="..\disassembler\LLVMDisassembler.cpp" />
     <ClInclude Include="..\dfg\DFGDesiredWeakReferences.h" />
     <ClInclude Include="..\dfg\DFGDesiredWriteBarriers.h" />
     <ClInclude Include="..\dfg\DFGDisassembler.h" />
+    <ClInclude Include="..\dfg\DFGDoesGC.h" />
     <ClInclude Include="..\dfg\DFGDominators.h" />
     <ClInclude Include="..\dfg\DFGDoubleFormatState.h" />
     <ClInclude Include="..\dfg\DFGDriver.h" />
     <ClInclude Include="..\dfg\DFGStoreBarrierElisionPhase.h" />
     <ClInclude Include="..\dfg\DFGStrengthReductionPhase.h" />
     <ClInclude Include="..\dfg\DFGStructureAbstractValue.h" />
+    <ClInclude Include="..\dfg\DFGStructureClobberState.h" />
     <ClInclude Include="..\dfg\DFGThreadData.h" />
     <ClInclude Include="..\dfg\DFGThunks.h" />
     <ClInclude Include="..\dfg\DFGTierUpCheckInjectionPhase.h" />
     <ClInclude Include="..\dfg\DFGToFTLDeferredCompilationCallback.h" />
     <ClInclude Include="..\dfg\DFGToFTLForOSREntryDeferredCompilationCallback.h" />
+    <ClInclude Include="..\dfg\DFGTransition.h" />
     <ClInclude Include="..\dfg\DFGTypeCheckHoistingPhase.h" />
     <ClInclude Include="..\dfg\DFGUnificationPhase.h" />
     <ClInclude Include="..\dfg\DFGUseKind.h" />
     <ClInclude Include="..\dfg\DFGVariableEventStream.h" />
     <ClInclude Include="..\dfg\DFGVariadicFunction.h" />
     <ClInclude Include="..\dfg\DFGVirtualRegisterAllocationPhase.h" />
+    <ClInclude Include="..\dfg\DFGWatchableStructureWatchingPhase.h" />
     <ClInclude Include="..\dfg\DFGWatchpointCollectionPhase.h" />
     <ClInclude Include="..\dfg\DFGWorklist.h" />
     <ClInclude Include="..\disassembler\Disassembler.h" />
index d1426df..356ec95 100644 (file)
                0F4CED5F18CEA7AB00802FE0 /* PolymorphicGetByIdList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4CED5D18CEA7AB00802FE0 /* PolymorphicGetByIdList.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F4F29DF18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F4F29DD18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp */; };
                0F4F29E018B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4F29DE18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F50AF3C193E8B3900674EE8 /* DFGStructureClobberState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F50AF3B193E8B3900674EE8 /* DFGStructureClobberState.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F5541B11613C1FB00CE3E25 /* SpecialPointer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5541AF1613C1FB00CE3E25 /* SpecialPointer.cpp */; };
                0F5541B21613C1FB00CE3E25 /* SpecialPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5541B01613C1FB00CE3E25 /* SpecialPointer.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F55989817C86C5800A1E543 /* ToNativeFromValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F55989717C86C5600A1E543 /* ToNativeFromValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F56A1D515001CF4002992B1 /* ExecutionCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F56A1D415001CF2002992B1 /* ExecutionCounter.cpp */; };
                0F572D4F16879FDD00E57FBD /* ThunkGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F572D4D16879FDB00E57FBD /* ThunkGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F5780A218FE1E98001E72D9 /* PureNaN.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5780A118FE1E98001E72D9 /* PureNaN.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F5A1273192D9FDF008764A3 /* DFGDoesGC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5A1271192D9FDF008764A3 /* DFGDoesGC.cpp */; };
+               0F5A1274192D9FDF008764A3 /* DFGDoesGC.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5A1272192D9FDF008764A3 /* DFGDoesGC.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F5A52D017ADD717008ECB2D /* CopyToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5A52CF17ADD717008ECB2D /* CopyToken.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F5A6283188C98D40072C9DF /* FTLValueRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5A6281188C98D40072C9DF /* FTLValueRange.cpp */; };
                0F5A6284188C98D40072C9DF /* FTLValueRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5A6282188C98D40072C9DF /* FTLValueRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F885E111849A3BE00F1E3FA /* BytecodeUseDef.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F885E101849A3BE00F1E3FA /* BytecodeUseDef.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F893BDB1936E23C001211F4 /* DFGStructureAbstractValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F893BDA1936E23C001211F4 /* DFGStructureAbstractValue.cpp */; };
                0F8F2B95172E04A0007DBDA5 /* FTLLink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F2B93172E049E007DBDA5 /* FTLLink.cpp */; };
                0F8F2B96172E04A3007DBDA5 /* FTLLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8F2B94172E049E007DBDA5 /* FTLLink.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F8F2B99172F04FF007DBDA5 /* DFGDesiredIdentifiers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F2B97172F04FD007DBDA5 /* DFGDesiredIdentifiers.cpp */; };
                0FB14E1F18124ACE009B6B4D /* JITInlineCacheGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB14E1D18124ACE009B6B4D /* JITInlineCacheGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FB14E211812570B009B6B4D /* DFGInlineCacheWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB14E201812570B009B6B4D /* DFGInlineCacheWrapper.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FB14E2318130955009B6B4D /* DFGInlineCacheWrapperInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB14E2218130955009B6B4D /* DFGInlineCacheWrapperInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB438A319270B1D00E1FBC9 /* StructureSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB438A219270B1D00E1FBC9 /* StructureSet.cpp */; };
                0FB5467714F59B5C002C2989 /* LazyOperandValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5467614F59AD1002C2989 /* LazyOperandValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FB5467914F5C46B002C2989 /* LazyOperandValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */; };
                0FB5467B14F5C7E1002C2989 /* MethodOfGettingAValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FCEFADF180738C000472CE4 /* FTLLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFADD180738C000472CE4 /* FTLLocation.cpp */; };
                0FCEFAE0180738C000472CE4 /* FTLLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFADE180738C000472CE4 /* FTLLocation.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FD2C92416D01EE900C7803F /* StructureInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD2C92316D01EE900C7803F /* StructureInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FD2D4FE192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD2D4FC192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.cpp */; };
+               0FD2D4FF192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD2D4FD192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FD3C82614115D4000FD81CB /* DFGDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD3C82014115CF800FD81CB /* DFGDriver.cpp */; };
                0FD3C82814115D4F00FD81CB /* DFGDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD3C82214115D0E00FD81CB /* DFGDriver.h */; };
                0FD81AD2154FB4EE00983E72 /* DFGDominators.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD81ACF154FB4EB00983E72 /* DFGDominators.cpp */; };
                0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; };
+               0FE7211D193B9C590031F6ED /* DFGTransition.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE7211B193B9C590031F6ED /* DFGTransition.cpp */; };
+               0FE7211E193B9C590031F6ED /* DFGTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE7211C193B9C590031F6ED /* DFGTransition.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE8534B1723CDA500B618F5 /* DFGDesiredWatchpoints.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE853491723CDA500B618F5 /* DFGDesiredWatchpoints.cpp */; };
                0FE8534C1723CDA500B618F5 /* DFGDesiredWatchpoints.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE8534A1723CDA500B618F5 /* DFGDesiredWatchpoints.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE95F7918B5694700B531FB /* FTLDataSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE95F7718B5694700B531FB /* FTLDataSection.cpp */; };
                0F4CED5D18CEA7AB00802FE0 /* PolymorphicGetByIdList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolymorphicGetByIdList.h; sourceTree = "<group>"; };
                0F4F29DD18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStaticExecutionCountEstimationPhase.cpp; path = dfg/DFGStaticExecutionCountEstimationPhase.cpp; sourceTree = "<group>"; };
                0F4F29DE18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStaticExecutionCountEstimationPhase.h; path = dfg/DFGStaticExecutionCountEstimationPhase.h; sourceTree = "<group>"; };
+               0F50AF3B193E8B3900674EE8 /* DFGStructureClobberState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureClobberState.h; path = dfg/DFGStructureClobberState.h; sourceTree = "<group>"; };
                0F5541AF1613C1FB00CE3E25 /* SpecialPointer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpecialPointer.cpp; sourceTree = "<group>"; };
                0F5541B01613C1FB00CE3E25 /* SpecialPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpecialPointer.h; sourceTree = "<group>"; };
                0F55989717C86C5600A1E543 /* ToNativeFromValue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ToNativeFromValue.h; sourceTree = "<group>"; };
                0F56A1D415001CF2002992B1 /* ExecutionCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutionCounter.cpp; sourceTree = "<group>"; };
                0F572D4D16879FDB00E57FBD /* ThunkGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThunkGenerator.h; sourceTree = "<group>"; };
                0F5780A118FE1E98001E72D9 /* PureNaN.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PureNaN.h; sourceTree = "<group>"; };
+               0F5A1271192D9FDF008764A3 /* DFGDoesGC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDoesGC.cpp; path = dfg/DFGDoesGC.cpp; sourceTree = "<group>"; };
+               0F5A1272192D9FDF008764A3 /* DFGDoesGC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDoesGC.h; path = dfg/DFGDoesGC.h; sourceTree = "<group>"; };
                0F5A52CF17ADD717008ECB2D /* CopyToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyToken.h; sourceTree = "<group>"; };
                0F5A6281188C98D40072C9DF /* FTLValueRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLValueRange.cpp; path = ftl/FTLValueRange.cpp; sourceTree = "<group>"; };
                0F5A6282188C98D40072C9DF /* FTLValueRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLValueRange.h; path = ftl/FTLValueRange.h; sourceTree = "<group>"; };
                0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayAllocationProfile.h; sourceTree = "<group>"; };
                0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBranchDirection.h; path = dfg/DFGBranchDirection.h; sourceTree = "<group>"; };
                0F885E101849A3BE00F1E3FA /* BytecodeUseDef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeUseDef.h; sourceTree = "<group>"; };
+               0F893BDA1936E23C001211F4 /* DFGStructureAbstractValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStructureAbstractValue.cpp; path = dfg/DFGStructureAbstractValue.cpp; sourceTree = "<group>"; };
                0F8F2B93172E049E007DBDA5 /* FTLLink.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FTLLink.cpp; path = ftl/FTLLink.cpp; sourceTree = "<group>"; };
                0F8F2B94172E049E007DBDA5 /* FTLLink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FTLLink.h; path = ftl/FTLLink.h; sourceTree = "<group>"; };
                0F8F2B97172F04FD007DBDA5 /* DFGDesiredIdentifiers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDesiredIdentifiers.cpp; path = dfg/DFGDesiredIdentifiers.cpp; sourceTree = "<group>"; };
                0FB14E1D18124ACE009B6B4D /* JITInlineCacheGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITInlineCacheGenerator.h; sourceTree = "<group>"; };
                0FB14E201812570B009B6B4D /* DFGInlineCacheWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInlineCacheWrapper.h; path = dfg/DFGInlineCacheWrapper.h; sourceTree = "<group>"; };
                0FB14E2218130955009B6B4D /* DFGInlineCacheWrapperInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInlineCacheWrapperInlines.h; path = dfg/DFGInlineCacheWrapperInlines.h; sourceTree = "<group>"; };
+               0FB438A219270B1D00E1FBC9 /* StructureSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureSet.cpp; sourceTree = "<group>"; };
                0FB4B51016B3A964003F696B /* DFGMinifiedID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGMinifiedID.h; path = dfg/DFGMinifiedID.h; sourceTree = "<group>"; };
                0FB4B51916B62772003F696B /* DFGAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAllocator.h; path = dfg/DFGAllocator.h; sourceTree = "<group>"; };
                0FB4B51A16B62772003F696B /* DFGCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCommon.cpp; path = dfg/DFGCommon.cpp; sourceTree = "<group>"; };
                0FCEFADD180738C000472CE4 /* FTLLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLLocation.cpp; path = ftl/FTLLocation.cpp; sourceTree = "<group>"; };
                0FCEFADE180738C000472CE4 /* FTLLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLLocation.h; path = ftl/FTLLocation.h; sourceTree = "<group>"; };
                0FD2C92316D01EE900C7803F /* StructureInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureInlines.h; sourceTree = "<group>"; };
+               0FD2D4FC192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGWatchableStructureWatchingPhase.cpp; path = dfg/DFGWatchableStructureWatchingPhase.cpp; sourceTree = "<group>"; };
+               0FD2D4FD192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGWatchableStructureWatchingPhase.h; path = dfg/DFGWatchableStructureWatchingPhase.h; sourceTree = "<group>"; };
                0FD3C82014115CF800FD81CB /* DFGDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDriver.cpp; path = dfg/DFGDriver.cpp; sourceTree = "<group>"; };
                0FD3C82214115D0E00FD81CB /* DFGDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDriver.h; path = dfg/DFGDriver.h; sourceTree = "<group>"; };
                0FD5652216AB780A00197653 /* DFGBasicBlockInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBasicBlockInlines.h; path = dfg/DFGBasicBlockInlines.h; sourceTree = "<group>"; };
                0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessDataDump.h; path = dfg/DFGVariableAccessDataDump.h; sourceTree = "<group>"; };
                0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; };
                0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; };
+               0FE7211B193B9C590031F6ED /* DFGTransition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGTransition.cpp; path = dfg/DFGTransition.cpp; sourceTree = "<group>"; };
+               0FE7211C193B9C590031F6ED /* DFGTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGTransition.h; path = dfg/DFGTransition.h; sourceTree = "<group>"; };
                0FE853491723CDA500B618F5 /* DFGDesiredWatchpoints.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDesiredWatchpoints.cpp; path = dfg/DFGDesiredWatchpoints.cpp; sourceTree = "<group>"; };
                0FE8534A1723CDA500B618F5 /* DFGDesiredWatchpoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDesiredWatchpoints.h; path = dfg/DFGDesiredWatchpoints.h; sourceTree = "<group>"; };
                0FE95F7718B5694700B531FB /* FTLDataSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLDataSection.cpp; path = ftl/FTLDataSection.cpp; sourceTree = "<group>"; };
                                C2981FDB17BAFF4400A3BC98 /* DFGDesiredWriteBarriers.h */,
                                0FF427611591A1C9004CB9FF /* DFGDisassembler.cpp */,
                                0FF427621591A1C9004CB9FF /* DFGDisassembler.h */,
+                               0F5A1271192D9FDF008764A3 /* DFGDoesGC.cpp */,
+                               0F5A1272192D9FDF008764A3 /* DFGDoesGC.h */,
                                0FD81ACF154FB4EB00983E72 /* DFGDominators.cpp */,
                                0FD81AD0154FB4EB00983E72 /* DFGDominators.h */,
                                0F1E3A441534CBAD000F9456 /* DFGDoubleFormatState.h */,
                                0F9D339517FFC4E60073C2BC /* DFGFlushedAt.h */,
                                A7D89CE817A0B8CC00773AD8 /* DFGFlushFormat.cpp */,
                                A7D89CE917A0B8CC00773AD8 /* DFGFlushFormat.h */,
+                               2A88067619107D5500CB0BBB /* DFGFunctionWhitelist.cpp */,
+                               2A88067719107D5500CB0BBB /* DFGFunctionWhitelist.h */,
                                86EC9DB61328DF82002B2AD7 /* DFGGenerationInfo.h */,
                                86EC9DB71328DF82002B2AD7 /* DFGGraph.cpp */,
                                86EC9DB81328DF82002B2AD7 /* DFGGraph.h */,
                                2ACCF3DD185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h */,
                                0FC20CB31852E2C600C9E954 /* DFGStrengthReductionPhase.cpp */,
                                0FC20CB41852E2C600C9E954 /* DFGStrengthReductionPhase.h */,
+                               0F893BDA1936E23C001211F4 /* DFGStructureAbstractValue.cpp */,
                                0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */,
+                               0F50AF3B193E8B3900674EE8 /* DFGStructureClobberState.h */,
                                0F2FCCF718A60070001A27F8 /* DFGThreadData.cpp */,
                                0F2FCCF818A60070001A27F8 /* DFGThreadData.h */,
                                0FC0979F146B28C700CF2442 /* DFGThunks.cpp */,
                                0FD8A32217D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.h */,
                                0FD8A32317D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp */,
                                0FD8A32417D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.h */,
+                               0FE7211B193B9C590031F6ED /* DFGTransition.cpp */,
+                               0FE7211C193B9C590031F6ED /* DFGTransition.h */,
                                0F63943C15C75F14006A597C /* DFGTypeCheckHoistingPhase.cpp */,
                                0F63943D15C75F14006A597C /* DFGTypeCheckHoistingPhase.h */,
                                0FBE0F6F16C1DB010082C5E8 /* DFGUnificationPhase.cpp */,
                                0F2BDC431522801700CD8910 /* DFGVariableEventStream.h */,
                                0FFFC95314EF909500C72532 /* DFGVirtualRegisterAllocationPhase.cpp */,
                                0FFFC95414EF909500C72532 /* DFGVirtualRegisterAllocationPhase.h */,
+                               0FD2D4FC192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.cpp */,
+                               0FD2D4FD192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.h */,
                                0FC97F3B18202119002C9B26 /* DFGWatchpointCollectionPhase.cpp */,
                                0FC97F3C18202119002C9B26 /* DFGWatchpointCollectionPhase.h */,
                                0FDB2CE5174830A2007B3C1B /* DFGWorklist.cpp */,
                                0FDB2CE6174830A2007B3C1B /* DFGWorklist.h */,
-                               2A88067619107D5500CB0BBB /* DFGFunctionWhitelist.cpp */,
-                               2A88067719107D5500CB0BBB /* DFGFunctionWhitelist.h */,
                        );
                        name = dfg;
                        sourceTree = "<group>";
                                0F5541B01613C1FB00CE3E25 /* SpecialPointer.h */,
                                0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */,
                                0FD82E4F141DAEA100179C94 /* SpeculatedType.h */,
+                               0FB438A219270B1D00E1FBC9 /* StructureSet.cpp */,
                                0F93329B14CA7DC10085F3C6 /* StructureSet.h */,
                                0F766D3615AE4A1A008F363E /* StructureStubClearingWatchpoint.cpp */,
                                0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */,
                                0F485328187DFDEC0083B687 /* FTLAvailableRecovery.h in Headers */,
                                0FEA0A0A170513DB00BB722C /* FTLCapabilities.h in Headers */,
                                0FEA0A231709606900BB722C /* FTLCommonValues.h in Headers */,
+                               0FD2D4FF192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.h in Headers */,
                                0FEA0A0C170513DB00BB722C /* FTLCompile.h in Headers */,
                                0FE95F7A18B5694700B531FB /* FTLDataSection.h in Headers */,
                                2AC922BC18A16182003CE0FB /* FTLDWARFDebugLineInfo.h in Headers */,
                                0F6B1CC61862C47800845D97 /* FTLUnwindInfo.h in Headers */,
                                0F235BE417178E1C00690C7F /* FTLValueFormat.h in Headers */,
                                0FDB2CCA173DA523007B3C1B /* FTLValueFromBlock.h in Headers */,
+                               0FE7211E193B9C590031F6ED /* DFGTransition.h in Headers */,
                                0F5A6284188C98D40072C9DF /* FTLValueRange.h in Headers */,
                                0F0332C618B53FA9005F979A /* FTLWeight.h in Headers */,
                                0F0332C818B546EC005F979A /* FTLWeightedTarget.h in Headers */,
                                0F2B66F217B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructor.h in Headers */,
                                0F2B66F317B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructorInlines.h in Headers */,
                                0F2B66F417B6B5AB00A7AE3F /* JSGenericTypedArrayViewInlines.h in Headers */,
+                               0F5A1274192D9FDF008764A3 /* DFGDoesGC.h in Headers */,
                                0F2B66F517B6B5AB00A7AE3F /* JSGenericTypedArrayViewPrototype.h in Headers */,
                                0F2B66F617B6B5AB00A7AE3F /* JSGenericTypedArrayViewPrototypeInlines.h in Headers */,
                                BC18C4210E16F5CD00B34460 /* JSGlobalObject.h in Headers */,
                                0F6B1CBA1861244C00845D97 /* RegisterPreservationMode.h in Headers */,
                                0F6B1CBE1861246A00845D97 /* RegisterPreservationWrapperGenerator.h in Headers */,
                                0FC314121814559100033232 /* RegisterSet.h in Headers */,
+                               0F50AF3C193E8B3900674EE8 /* DFGStructureClobberState.h in Headers */,
                                A57D23EE1891B5540031C7FA /* RegularExpression.h in Headers */,
                                0FB7F39D15ED8E4600F167B2 /* Reject.h in Headers */,
                                A5BA15E8182340B300A82E69 /* RemoteInspector.h in Headers */,
                                0FF0F19916B729F6005DF95B /* DFGLongLivedState.cpp in Sources */,
                                A767B5B517A0B9650063D940 /* DFGLoopPreHeaderCreationPhase.cpp in Sources */,
                                0F2BDC4D1522818600CD8910 /* DFGMinifiedNode.cpp in Sources */,
+                               0FD2D4FE192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.cpp in Sources */,
                                A737810D1799EA2E00817533 /* DFGNaturalLoops.cpp in Sources */,
                                0FF0F19C16B72A03005DF95B /* DFGNode.cpp in Sources */,
                                0FA581BA150E952C00B9A2D9 /* DFGNodeFlags.cpp in Sources */,
                                0FC20CB918556A3500C9E954 /* DFGSSALoweringPhase.cpp in Sources */,
                                0F9FB4F417FCB91700CB67F8 /* DFGStackLayoutPhase.cpp in Sources */,
                                0F4F29DF18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp in Sources */,
+                               0FE7211D193B9C590031F6ED /* DFGTransition.cpp in Sources */,
                                2ACCF3DE185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp in Sources */,
                                0FC20CB51852E2C600C9E954 /* DFGStrengthReductionPhase.cpp in Sources */,
                                0F2FCCFE18A60070001A27F8 /* DFGThreadData.cpp in Sources */,
                                0F235BE117178E1C00690C7F /* FTLThunks.cpp in Sources */,
                                0F6B1CC51862C47800845D97 /* FTLUnwindInfo.cpp in Sources */,
                                0F235BE317178E1C00690C7F /* FTLValueFormat.cpp in Sources */,
+                               0F5A1273192D9FDF008764A3 /* DFGDoesGC.cpp in Sources */,
                                A53CE08718BC1A5600BEDF76 /* JSConsole.cpp in Sources */,
                                0F5A6283188C98D40072C9DF /* FTLValueRange.cpp in Sources */,
                                147F39CB107EC37600427A48 /* FunctionConstructor.cpp in Sources */,
                                95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */,
                                7C184E1A17BEDBD3007CB63A /* JSPromise.cpp in Sources */,
                                7C184E2217BEE240007CB63A /* JSPromiseConstructor.cpp in Sources */,
+                               0F893BDB1936E23C001211F4 /* DFGStructureAbstractValue.cpp in Sources */,
                                7C008CDA187124BB00955C24 /* JSPromiseDeferred.cpp in Sources */,
                                7C008CD2186F8A9300955C24 /* JSPromiseFunctions.cpp in Sources */,
                                7C184E1E17BEE22E007CB63A /* JSPromisePrototype.cpp in Sources */,
                                2A83638918D7D0FE0000EBCC /* FullGCActivityCallback.cpp in Sources */,
                                1428083A107EC0750013E7B2 /* JSStack.cpp in Sources */,
                                147F39D5107EC37600427A48 /* JSString.cpp in Sources */,
+                               0FB438A319270B1D00E1FBC9 /* StructureSet.cpp in Sources */,
                                2600B5A6152BAAA70091EE5F /* JSStringJoiner.cpp in Sources */,
                                1482B74E0A43032800517CFC /* JSStringRef.cpp in Sources */,
                                146AAB380B66A94400E55F16 /* JSStringRefCF.cpp in Sources */,
diff --git a/Source/JavaScriptCore/bytecode/StructureSet.cpp b/Source/JavaScriptCore/bytecode/StructureSet.cpp
new file mode 100644 (file)
index 0000000..eead0d6
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "StructureSet.h"
+
+#include <wtf/CommaPrinter.h>
+
+namespace JSC {
+
+void StructureSet::clear()
+{
+    deleteStructureListIfNecessary();
+    setEmpty();
+}
+
+bool StructureSet::add(Structure* structure)
+{
+    ASSERT(structure);
+    if (isThin()) {
+        if (singleStructure() == structure)
+            return false;
+        if (!singleStructure()) {
+            set(structure);
+            return true;
+        }
+        OutOfLineList* list = OutOfLineList::create(defaultStartingSize);
+        list->m_length = 2;
+        list->list()[0] = singleStructure();
+        list->list()[1] = structure;
+        set(list);
+        return true;
+    }
+    
+    return addOutOfLine(structure);
+}
+
+bool StructureSet::remove(Structure* structure)
+{
+    if (isThin()) {
+        if (singleStructure() == structure) {
+            setEmpty();
+            return true;
+        }
+        return false;
+    }
+    
+    OutOfLineList* list = structureList();
+    for (unsigned i = 0; i < list->m_length; ++i) {
+        if (list->list()[i] != structure)
+            continue;
+        list->list()[i] = list->list()[--list->m_length];
+        if (!list->m_length) {
+            OutOfLineList::destroy(list);
+            setEmpty();
+        }
+        return true;
+    }
+    return false;
+}
+
+bool StructureSet::contains(Structure* structure) const
+{
+    if (isThin())
+        return singleStructure() == structure;
+
+    return containsOutOfLine(structure);
+}
+
+bool StructureSet::merge(const StructureSet& other)
+{
+    if (other.isThin()) {
+        if (other.singleStructure())
+            return add(other.singleStructure());
+        return false;
+    }
+    
+    OutOfLineList* list = other.structureList();
+    if (list->m_length >= 2) {
+        if (isThin()) {
+            OutOfLineList* myNewList = OutOfLineList::create(
+                list->m_length + !!singleStructure());
+            if (singleStructure()) {
+                myNewList->m_length = 1;
+                myNewList->list()[0] = singleStructure();
+            }
+            set(myNewList);
+        }
+        bool changed = false;
+        for (unsigned i = 0; i < list->m_length; ++i)
+            changed |= addOutOfLine(list->list()[i]);
+        return changed;
+    }
+    
+    ASSERT(list->m_length);
+    return add(list->list()[0]);
+}
+
+void StructureSet::filter(const StructureSet& other)
+{
+    if (other.isThin()) {
+        if (!other.singleStructure() || !contains(other.singleStructure()))
+            clear();
+        else {
+            clear();
+            set(other.singleStructure());
+        }
+        return;
+    }
+    
+    ContainsOutOfLine containsOutOfLine(other);
+    genericFilter(containsOutOfLine);
+}
+
+void StructureSet::exclude(const StructureSet& other)
+{
+    if (other.isThin()) {
+        if (other.singleStructure())
+            remove(other.singleStructure());
+        return;
+    }
+    
+    if (isThin()) {
+        if (!singleStructure())
+            return;
+        if (other.contains(singleStructure()))
+            clear();
+        return;
+    }
+    
+    OutOfLineList* list = structureList();
+    for (unsigned i = 0; i < list->m_length; ++i) {
+        if (!other.containsOutOfLine(list->list()[i]))
+            continue;
+        list->list()[i--] = list->list()[--list->m_length];
+    }
+    if (!list->m_length)
+        clear();
+}
+
+bool StructureSet::isSubsetOf(const StructureSet& other) const
+{
+    if (isThin()) {
+        if (!singleStructure())
+            return true;
+        return other.contains(singleStructure());
+    }
+    
+    if (other.isThin()) {
+        if (!other.singleStructure())
+            return false;
+        OutOfLineList* list = structureList();
+        if (list->m_length >= 2)
+            return false;
+        if (list->list()[0] == other.singleStructure())
+            return true;
+        return false;
+    }
+    
+    OutOfLineList* list = structureList();
+    for (unsigned i = 0; i < list->m_length; ++i) {
+        if (!other.containsOutOfLine(list->list()[i]))
+            return false;
+    }
+    return true;
+}
+
+bool StructureSet::overlaps(const StructureSet& other) const
+{
+    if (isThin()) {
+        if (!singleStructure())
+            return false;
+        return other.contains(singleStructure());
+    }
+    
+    if (other.isThin()) {
+        if (!other.singleStructure())
+            return false;
+        return containsOutOfLine(other.singleStructure());
+    }
+    
+    OutOfLineList* list = structureList();
+    for (unsigned i = 0; i < list->m_length; ++i) {
+        if (other.containsOutOfLine(list->list()[i]))
+            return true;
+    }
+    return false;
+}
+
+bool StructureSet::operator==(const StructureSet& other) const
+{
+    if (size() != other.size())
+        return false;
+    return isSubsetOf(other);
+}
+
+SpeculatedType StructureSet::speculationFromStructures() const
+{
+    if (isThin()) {
+        if (!singleStructure())
+            return SpecNone;
+        return speculationFromStructure(singleStructure());
+    }
+    
+    SpeculatedType result = SpecNone;
+    OutOfLineList* list = structureList();
+    for (unsigned i = 0; i < list->m_length; ++i)
+        mergeSpeculation(result, speculationFromStructure(list->list()[i]));
+    return result;
+}
+
+ArrayModes StructureSet::arrayModesFromStructures() const
+{
+    if (isThin()) {
+        if (!singleStructure())
+            return 0;
+        return asArrayModes(singleStructure()->indexingType());
+    }
+    
+    ArrayModes result = 0;
+    OutOfLineList* list = structureList();
+    for (unsigned i = 0; i < list->m_length; ++i)
+        mergeArrayModes(result, asArrayModes(list->list()[i]->indexingType()));
+    return result;
+}
+
+void StructureSet::dumpInContext(PrintStream& out, DumpContext* context) const
+{
+    CommaPrinter comma;
+    out.print("[");
+    for (size_t i = 0; i < size(); ++i)
+        out.print(comma, inContext(*at(i), context));
+    out.print("]");
+}
+
+void StructureSet::dump(PrintStream& out) const
+{
+    dumpInContext(out, nullptr);
+}
+
+bool StructureSet::addOutOfLine(Structure* structure)
+{
+    OutOfLineList* list = structureList();
+    for (unsigned i = 0; i < list->m_length; ++i) {
+        if (list->list()[i] == structure)
+            return false;
+    }
+    
+    if (list->m_length < list->m_capacity) {
+        list->list()[list->m_length++] = structure;
+        return true;
+    }
+    
+    OutOfLineList* newList = OutOfLineList::create(list->m_capacity * 2);
+    newList->m_length = list->m_length + 1;
+    for (unsigned i = list->m_length; i--;)
+        newList->list()[i] = list->list()[i];
+    newList->list()[list->m_length] = structure;
+    set(newList);
+    return true;
+}
+
+bool StructureSet::containsOutOfLine(Structure* structure) const
+{
+    OutOfLineList* list = structureList();
+    for (unsigned i = 0; i < list->m_length; ++i) {
+        if (list->list()[i] == structure)
+            return true;
+    }
+    return false;
+}
+
+void StructureSet::copyFromOutOfLine(const StructureSet& other)
+{
+    ASSERT(!other.isThin() && other.m_pointer != reservedValue);
+    OutOfLineList* otherList = other.structureList();
+    OutOfLineList* myList = OutOfLineList::create(otherList->m_length);
+    myList->m_length = otherList->m_length;
+    for (unsigned i = otherList->m_length; i--;)
+        myList->list()[i] = otherList->list()[i];
+    set(myList);
+}
+
+StructureSet::OutOfLineList* StructureSet::OutOfLineList::create(unsigned capacity)
+{
+    return new (NotNull, fastMalloc(sizeof(OutOfLineList) + capacity * sizeof(Structure*))) OutOfLineList(0, capacity);
+}
+
+void StructureSet::OutOfLineList::destroy(OutOfLineList* list)
+{
+    fastFree(list);
+}
+
+} // namespace JSC
+
index d7087b9..0e9a467 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,8 +30,6 @@
 #include "SpeculatedType.h"
 #include "Structure.h"
 #include "DumpContext.h"
-#include <wtf/CommaPrinter.h>
-#include <wtf/Vector.h>
 
 namespace JSC {
 
@@ -41,156 +39,238 @@ class StructureAbstractValue;
 
 class StructureSet {
 public:
-    StructureSet() { }
-    
-    StructureSet(Structure* structure)
+    StructureSet()
     {
-        ASSERT(structure);
-        m_structures.append(structure);
+        setEmpty();
     }
     
-    void clear()
+    StructureSet(Structure* structure)
     {
-        m_structures.clear();
+        set(structure);
     }
     
-    void add(Structure* structure)
+    ALWAYS_INLINE StructureSet(const StructureSet& other)
     {
-        ASSERT(structure);
-        ASSERT(!contains(structure));
-        m_structures.append(structure);
+        copyFrom(other);
     }
     
-    bool addAll(const StructureSet& other)
+    ALWAYS_INLINE StructureSet& operator=(const StructureSet& other)
     {
-        bool changed = false;
-        for (size_t i = 0; i < other.size(); ++i) {
-            if (contains(other[i]))
-                continue;
-            add(other[i]);
-            changed = true;
-        }
-        return changed;
+        if (this == &other)
+            return *this;
+        deleteStructureListIfNecessary();
+        copyFrom(other);
+        return *this;
     }
     
-    void remove(Structure* structure)
+    ~StructureSet()
     {
-        for (size_t i = 0; i < m_structures.size(); ++i) {
-            if (m_structures[i] != structure)
-                continue;
-            
-            m_structures[i] = m_structures.last();
-            m_structures.removeLast();
-            return;
-        }
+        deleteStructureListIfNecessary();
     }
     
-    bool contains(Structure* structure) const
+    void clear();
+    
+    Structure* onlyStructure() const
     {
-        for (size_t i = 0; i < m_structures.size(); ++i) {
-            if (m_structures[i] == structure)
-                return true;
+        if (isThin()) {
+            ASSERT(singleStructure());
+            return singleStructure();
         }
-        return false;
+        ASSERT(structureList()->m_length == 1);
+        return structureList()->list()[0];
     }
     
-    bool containsOnly(Structure* structure) const
+    bool isEmpty() const
     {
-        if (size() != 1)
-            return false;
-        return singletonStructure() == structure;
+        bool result = isThin() && !singleStructure();
+        if (result)
+            ASSERT(m_pointer != reservedValue);
+        return result;
     }
     
-    bool isSubsetOf(const StructureSet& other) const
+    bool add(Structure*);
+    bool remove(Structure*);
+    bool contains(Structure*) const;
+    
+    bool merge(const StructureSet&);
+    void filter(const StructureSet&);
+    void exclude(const StructureSet&);
+    
+    template<typename Functor>
+    void genericFilter(Functor& functor)
     {
-        for (size_t i = 0; i < m_structures.size(); ++i) {
-            if (!other.contains(m_structures[i]))
-                return false;
+        if (isThin()) {
+            if (!singleStructure())
+                return;
+            if (functor(singleStructure()))
+                return;
+            clear();
+            return;
+        }
+        
+        OutOfLineList* list = structureList();
+        for (unsigned i = 0; i < list->m_length; ++i) {
+            if (functor(list->list()[i]))
+                continue;
+            list->list()[i--] = list->list()[--list->m_length];
         }
-        return true;
+        if (!list->m_length)
+            clear();
     }
     
+    bool isSubsetOf(const StructureSet&) const;
     bool isSupersetOf(const StructureSet& other) const
     {
         return other.isSubsetOf(*this);
     }
     
-    bool overlaps(const StructureSet& other) const
+    bool overlaps(const StructureSet&) const;
+    
+    size_t size() const
+    {
+        if (isThin())
+            return !!singleStructure();
+        return structureList()->m_length;
+    }
+    
+    Structure* at(size_t i) const
     {
-        for (size_t i = 0; i < m_structures.size(); ++i) {
-            if (other.contains(m_structures[i]))
-                return true;
+        if (isThin()) {
+            ASSERT(!i);
+            ASSERT(singleStructure());
+            return singleStructure();
         }
-        return false;
+        ASSERT(i < structureList()->m_length);
+        return structureList()->list()[i];
     }
     
-    size_t size() const { return m_structures.size(); }
+    Structure* operator[](size_t i) const { return at(i); }
     
-    // Call this if you know that the structure set must consist of exactly
-    // one structure.
-    Structure* singletonStructure() const
+    Structure* last() const
     {
-        ASSERT(m_structures.size() == 1);
-        return m_structures[0];
+        if (isThin()) {
+            ASSERT(singleStructure());
+            return singleStructure();
+        }
+        return structureList()->list()[structureList()->m_length - 1];
     }
     
-    Structure* at(size_t i) const { return m_structures.at(i); }
+    bool operator==(const StructureSet& other) const;
     
-    Structure* operator[](size_t i) const { return at(i); }
+    SpeculatedType speculationFromStructures() const;
+    ArrayModes arrayModesFromStructures() const;
+    
+    void dumpInContext(PrintStream&, DumpContext*) const;
+    void dump(PrintStream&) const;
     
-    Structure* last() const { return m_structures.last(); }
+private:
+    friend class DFG::StructureAbstractValue;
+    
+    static const uintptr_t thinFlag = 1;
+    static const uintptr_t reservedFlag = 2;
+    static const uintptr_t flags = thinFlag | reservedFlag;
+    static const uintptr_t reservedValue = 4;
 
-    SpeculatedType speculationFromStructures() const
-    {
-        SpeculatedType result = SpecNone;
-        
-        for (size_t i = 0; i < m_structures.size(); ++i)
-            mergeSpeculation(result, speculationFromStructure(m_structures[i]));
+    static const unsigned defaultStartingSize = 4;
+    
+    bool addOutOfLine(Structure*);
+    bool containsOutOfLine(Structure*) const;
+    
+    class ContainsOutOfLine {
+    public:
+        ContainsOutOfLine(const StructureSet& set)
+            : m_set(set)
+        {
+        }
         
-        return result;
+        bool operator()(Structure* structure)
+        {
+            return m_set.containsOutOfLine(structure);
+        }
+    private:
+        const StructureSet& m_set;
+    };
+
+    ALWAYS_INLINE void copyFrom(const StructureSet& other)
+    {
+        if (other.isThin() || other.m_pointer == reservedValue) {
+            bool value = getReservedFlag();
+            m_pointer = other.m_pointer;
+            setReservedFlag(value);
+            return;
+        }
+        copyFromOutOfLine(other);
     }
+    void copyFromOutOfLine(const StructureSet& other);
     
-    ArrayModes arrayModesFromStructures() const
-    {
-        ArrayModes result = 0;
+    class OutOfLineList {
+    public:
+        static OutOfLineList* create(unsigned capacity);
+        static void destroy(OutOfLineList*);
         
-        for (size_t i = 0; i < m_structures.size(); ++i)
-            mergeArrayModes(result, asArrayModes(m_structures[i]->indexingType()));
+        Structure** list() { return bitwise_cast<Structure**>(this + 1); }
         
-        return result;
-    }
+        OutOfLineList(unsigned length, unsigned capacity)
+            : m_length(length)
+            , m_capacity(capacity)
+        {
+        }
+
+        unsigned m_length;
+        unsigned m_capacity;
+    };
     
-    bool operator==(const StructureSet& other) const
+    ALWAYS_INLINE void deleteStructureListIfNecessary()
     {
-        if (m_structures.size() != other.m_structures.size())
-            return false;
-        
-        for (size_t i = 0; i < m_structures.size(); ++i) {
-            if (!other.contains(m_structures[i]))
-                return false;
-        }
-        
-        return true;
+        if (!isThin() && m_pointer != reservedValue)
+            OutOfLineList::destroy(structureList());
     }
     
-    void dumpInContext(PrintStream& out, DumpContext* context) const
+    bool isThin() const { return m_pointer & thinFlag; }
+    
+    void* pointer() const
     {
-        CommaPrinter comma;
-        out.print("[");
-        for (size_t i = 0; i < m_structures.size(); ++i)
-            out.print(comma, inContext(*m_structures[i], context));
-        out.print("]");
+        return bitwise_cast<void*>(m_pointer & ~flags);
     }
     
-    void dump(PrintStream& out) const
+    Structure* singleStructure() const
     {
-        dumpInContext(out, 0);
+        ASSERT(isThin());
+        return static_cast<Structure*>(pointer());
     }
     
-private:
-    friend class DFG::StructureAbstractValue;
+    OutOfLineList* structureList() const
+    {
+        ASSERT(!isThin());
+        return static_cast<OutOfLineList*>(pointer());
+    }
     
-    Vector<Structure*, 2> m_structures;
+    void set(Structure* structure)
+    {
+        set(bitwise_cast<uintptr_t>(structure), true);
+    }
+    void set(OutOfLineList* structures)
+    {
+        set(bitwise_cast<uintptr_t>(structures), false);
+    }
+    void setEmpty()
+    {
+        set(0, true);
+    }
+    void set(uintptr_t pointer, bool singleStructure)
+    {
+        m_pointer = pointer | (singleStructure ? thinFlag : 0) | (m_pointer & reservedFlag);
+    }
+    bool getReservedFlag() const { return m_pointer & reservedFlag; }
+    void setReservedFlag(bool value)
+    {
+        if (value)
+            m_pointer |= reservedFlag;
+        else
+            m_pointer &= ~reservedFlag;
+    }
+
+    uintptr_t m_pointer;
 };
 
 } // namespace JSC
index 7c422e7..9507653 100644 (file)
@@ -70,8 +70,7 @@ namespace JSC { namespace DFG {
     macro(ArrayStorageProperties) \
     macro(Variables) \
     macro(TypedArrayProperties) \
-    macro(GCState) \
-    macro(BarrierState) \
+    macro(HeapObjectCount) /* Used to reflect the fact that some allocations reveal object identity */\
     macro(RegExpState) \
     macro(InternalState) \
     macro(Absolute) \
index 97582ac..01f5a48 100644 (file)
@@ -114,6 +114,7 @@ public:
     bool executeEffects(unsigned indexInBlock);
     bool executeEffects(unsigned clobberLimit, Node*);
     
+    void dump(PrintStream& out) const;
     void dump(PrintStream& out);
     
     template<typename T>
@@ -148,7 +149,14 @@ public:
 private:
     void clobberWorld(const CodeOrigin&, unsigned indexInBlock);
     void clobberCapturedVars(const CodeOrigin&);
+    
+    template<typename Functor>
+    void forAllValues(unsigned indexInBlock, Functor&);
+    
     void clobberStructures(unsigned indexInBlock);
+    void observeTransition(unsigned indexInBlock, Structure* from, Structure* to);
+    void observeTransitions(unsigned indexInBlock, const TransitionVector&);
+    void setDidClobber();
     
     enum BooleanResult {
         UnknownBooleanResult,
@@ -160,7 +168,7 @@ private:
     void setBuiltInConstant(Node* node, JSValue value)
     {
         AbstractValue& abstractValue = forNode(node);
-        abstractValue.set(m_graph, value);
+        abstractValue.set(m_graph, value, m_state.structureClobberState());
         abstractValue.fixTypeForRepresentation(node);
     }
     
index 5e51dea..ba7403f 100644 (file)
@@ -62,11 +62,17 @@ AbstractInterpreter<AbstractStateType>::booleanResult(
     }
 
     // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
-    if (isCellSpeculation(value.m_type)
-        && value.m_currentKnownStructure.hasSingleton()) {
-        Structure* structure = value.m_currentKnownStructure.singleton();
-        if (!structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
-            && structure->typeInfo().type() != StringType)
+    if (isCellSpeculation(value.m_type) && !value.m_structure.isTop()) {
+        bool allTrue = true;
+        for (unsigned i = value.m_structure.size(); i--;) {
+            Structure* structure = value.m_structure[i];
+            if (structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
+                || structure->typeInfo().type() == StringType) {
+                allTrue = false;
+                break;
+            }
+        }
+        if (allTrue)
             return DefinitelyTrue;
     }
     
@@ -105,9 +111,12 @@ void AbstractInterpreter<AbstractStateType>::executeEdges(unsigned indexInBlock)
 }
 
 template<typename AbstractStateType>
-void AbstractInterpreter<AbstractStateType>::verifyEdge(Node*, Edge edge)
+void AbstractInterpreter<AbstractStateType>::verifyEdge(Node* node, Edge edge)
 {
-    RELEASE_ASSERT(!(forNode(edge).m_type & ~typeFilterFor(edge.useKind())));
+    if (!(forNode(edge).m_type & ~typeFilterFor(edge.useKind())))
+        return;
+    
+    DFG_CRASH(m_graph, node, toCString("Edge verification error: ", node, "->", edge, " was expected to have type ", SpeculationDump(typeFilterFor(edge.useKind())), " but has type ", SpeculationDump(forNode(edge).m_type)).data());
 }
 
 template<typename AbstractStateType>
@@ -1273,7 +1282,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         forNode(node).set(
             m_graph,
             m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
-        m_state.setHaveStructures(true);
         break;
         
     case NewArrayBuffer:
@@ -1281,13 +1289,11 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         forNode(node).set(
             m_graph,
             m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
-        m_state.setHaveStructures(true);
         break;
 
     case NewArrayWithSize:
         node->setCanExit(true);
         forNode(node).setType(SpecArray);
-        m_state.setHaveStructures(true);
         break;
         
     case NewTypedArray:
@@ -1305,12 +1311,10 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             m_graph,
             m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructure(
                 node->typedArrayType()));
-        m_state.setHaveStructures(true);
         break;
             
     case NewRegexp:
         forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->regExpStructure());
-        m_state.setHaveStructures(true);
         break;
             
     case ToThis: {
@@ -1338,13 +1342,11 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case NewObject:
         ASSERT(node->structure());
         forNode(node).set(m_graph, node->structure());
-        m_state.setHaveStructures(true);
         break;
         
     case CreateActivation:
         forNode(node).set(
             m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->activationStructure());
-        m_state.setHaveStructures(true);
         break;
         
     case FunctionReentryWatchpoint:
@@ -1377,8 +1379,9 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         // of GetMyArgumentsLength, because GetMyArgumentsLength is a clobbering operation.
         // We perform further optimizations on this later on.
         if (node->origin.semantic.inlineCallFrame) {
-            forNode(node).set(
-                m_graph, jsNumber(node->origin.semantic.inlineCallFrame->arguments.size() - 1));
+            setConstant(
+                node, jsNumber(node->origin.semantic.inlineCallFrame->arguments.size() - 1));
+            m_state.setDidClobber(true); // Pretend that we clobbered to prevent constant folding.
         } else
             forNode(node).setType(SpecInt32);
         node->setCanExit(
@@ -1474,7 +1477,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             break;
         }
         if (isCellSpeculation(node->child1()->prediction())) {
-            if (Structure* structure = forNode(node->child1()).bestProvenStructure()) {
+            // This use of onlyStructure() should be replaced by giving GetByIdStatus the ability
+            // to compute things based on a StructureSet, and then to factor ByteCodeParser's
+            // ability to generate code based on a GetByIdStatus out of ByteCodeParser so that
+            // ConstantFoldingPhase can use it.
+            // https://bugs.webkit.org/show_bug.cgi?id=133229
+            if (Structure* structure = forNode(node->child1()).m_structure.onlyStructure()) {
                 GetByIdStatus status = GetByIdStatus::computeFor(
                     m_graph.m_vm, structure,
                     m_graph.identifiers()[node->identifierNumber()]);
@@ -1484,14 +1492,17 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
                     ASSERT(status[0].structureSet().size() == 1);
                     ASSERT(!status[0].chain());
                     
-                    if (status[0].specificValue())
+                    if (status[0].specificValue()) {
+                        if (status[0].specificValue().isCell()) {
+                            Structure* structure = status[0].specificValue().asCell()->structure();
+                            m_graph.watchpoints().consider(structure);
+                        }
                         setConstant(node, status[0].specificValue());
-                    else
+                    else
                         forNode(node).makeHeapTop();
                     filter(node->child1(), status[0].structureSet());
                     
                     m_state.setFoundConstants(true);
-                    m_state.setHaveStructures(true);
                     break;
                 }
             }
@@ -1520,44 +1531,28 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this.
 
         StructureSet& set = node->structureSet();
-
-        if (value.m_currentKnownStructure.isSubsetOf(set)) {
+        
+        // It's interesting that we could have proven that the object has a larger structure set
+        // that includes the set we're testing. In that case we could make the structure check
+        // more efficient. We currently don't.
+        
+        if (value.m_structure.isSubsetOf(set)) {
             m_state.setFoundConstants(true);
             break;
         }
 
         node->setCanExit(true);
-        m_state.setHaveStructures(true);
-
-        // If this structure check is attempting to prove knowledge already held in
-        // the futurePossibleStructure set then the constant folding phase should
-        // turn this into a watchpoint instead.
-        if (value.m_futurePossibleStructure.isSubsetOf(set)
-            && value.m_futurePossibleStructure.hasSingleton()) {
-            m_state.setFoundConstants(true);
-            filter(value, value.m_futurePossibleStructure.singleton());
-            break;
-        }
 
         filter(value, set);
         break;
     }
         
-    case StructureTransitionWatchpoint: {
-        AbstractValue& value = forNode(node->child1());
-
-        filter(value, node->structure());
-        m_state.setHaveStructures(true);
-        node->setCanExit(true);
-        break;
-    }
-            
     case PutStructure:
     case PhantomPutStructure:
-        if (!forNode(node->child1()).m_currentKnownStructure.isClear()) {
-            clobberStructures(clobberLimit);
-            forNode(node->child1()).set(m_graph, node->structureTransitionData().newStructure);
-            m_state.setHaveStructures(true);
+        if (!forNode(node->child1()).m_structure.isClear()) {
+            observeTransition(
+                clobberLimit, node->transition()->previous, node->transition()->next);
+            forNode(node->child1()).set(m_graph, node->transition()->next);
         }
         break;
     case GetButterfly:
@@ -1616,7 +1611,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             break;
         }
         filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
-        m_state.setHaveStructures(true);
         break;
     }
     case Arrayify: {
@@ -1629,19 +1623,43 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         node->setCanExit(true);
         clobberStructures(clobberLimit);
         filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
-        m_state.setHaveStructures(true);
         break;
     }
     case ArrayifyToStructure: {
         AbstractValue& value = forNode(node->child1());
-        StructureSet set = node->structure();
-        if (value.m_futurePossibleStructure.isSubsetOf(set)
-            || value.m_currentKnownStructure.isSubsetOf(set))
+        if (value.m_structure.isSubsetOf(StructureSet(node->structure())))
             m_state.setFoundConstants(true);
         node->setCanExit(true);
         clobberStructures(clobberLimit);
-        filter(value, set);
-        m_state.setHaveStructures(true);
+        
+        // We have a bunch of options of how to express the abstract set at this point. Let set S
+        // be the set of structures that the value had before clobbering and assume that all of
+        // them are watchable. The new value should be the least expressible upper bound of the
+        // intersection of "values that currently have structure = node->structure()" and "values
+        // that have structure in S plus any structure transition-reachable from S". Assume that
+        // node->structure() is not in S but it is transition-reachable from S. Then we would
+        // like to say that the result is "values that have structure = node->structure() until
+        // we invalidate", but there is no way to express this using the AbstractValue syntax. So
+        // we must choose between:
+        //
+        // 1) "values that currently have structure = node->structure()". This is a valid
+        //    superset of the value that we really want, and it's specific enough to satisfy the
+        //    preconditions of the array access that this is guarding. It's also specific enough
+        //    to allow relevant optimizations in the case that we didn't have a contradiction
+        //    like in this example. Notice that in the abscence of any contradiction, this result
+        //    is precise rather than being a conservative LUB.
+        //
+        // 2) "values that currently hava structure in S plus any structure transition-reachable
+        //    from S". This is also a valid superset of the value that we really want, but it's
+        //    not specific enough to satisfy the preconditions of the array access that this is
+        //    guarding - so playing such shenanigans would preclude us from having assertions on
+        //    the typing preconditions of any array accesses. This would also not be a desirable
+        //    answer in the absence of a contradiction.
+        //
+        // Note that it's tempting to simply say that the resulting value is BOTTOM because of
+        // the contradiction. That would be wrong, since we haven't hit an invalidation point,
+        // yet.
+        value.set(m_graph, node->structure());
         break;
     }
     case GetIndexedPropertyStorage:
@@ -1669,7 +1687,11 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         AbstractValue& value = forNode(node->child1());
         ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this.
 
-        if (Structure* structure = value.bestProvenStructure()) {
+        // This should just filter down the cases in MultiGetByOffset. If that results in all
+        // cases having the same offset then we should strength reduce it to a CheckStructure +
+        // GetByOffset.
+        // https://bugs.webkit.org/show_bug.cgi?id=133229
+        if (Structure* structure = value.m_structure.onlyStructure()) {
             bool done = false;
             for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) {
                 const GetByIdVariant& variant = node->multiGetByOffsetData().variants[i];
@@ -1691,7 +1713,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         
         StructureSet set;
         for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;)
-            set.addAll(node->multiGetByOffsetData().variants[i].structureSet());
+            set.merge(node->multiGetByOffsetData().variants[i].structureSet());
         
         filter(node->child1(), set);
         forNode(node).makeHeapTop();
@@ -1706,7 +1728,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         AbstractValue& value = forNode(node->child1());
         ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this.
 
-        if (Structure* structure = value.bestProvenStructure()) {
+        // This should just filter down the cases in MultiPutByOffset. If that results in either
+        // one case, or nothing but replace cases and they have the same offset, then we should
+        // just strength reduce it to the appropriate combination of CheckStructure,
+        // [Re]AllocatePropertyStorage, PutStructure, and PutByOffset.
+        // https://bugs.webkit.org/show_bug.cgi?id=133229
+        if (Structure* structure = value.m_structure.onlyStructure()) {
             bool done = false;
             for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
                 const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
@@ -1716,7 +1743,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
                 if (variant.kind() == PutByIdVariant::Replace) {
                     filter(node->child1(), structure);
                     m_state.setFoundConstants(true);
-                    m_state.setHaveStructures(true);
                     done = true;
                     break;
                 }
@@ -1725,7 +1751,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
                 clobberStructures(clobberLimit);
                 forNode(node->child1()).set(m_graph, variant.newStructure());
                 m_state.setFoundConstants(true);
-                m_state.setHaveStructures(true);
                 done = true;
                 break;
             }
@@ -1733,25 +1758,24 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
                 break;
         }
         
-        clobberStructures(clobberLimit);
-        
+        StructureSet oldSet;
         StructureSet newSet;
+        TransitionVector transitions;
         for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
             const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
-            if (variant.kind() == PutByIdVariant::Replace) {
-                if (value.m_currentKnownStructure.contains(variant.structure()))
-                    newSet.addAll(variant.structure());
-                continue;
+            oldSet.add(variant.oldStructure());
+            if (variant.kind() == PutByIdVariant::Transition) {
+                transitions.append(Transition(variant.oldStructure(), variant.newStructure()));
+                newSet.add(variant.newStructure());
+            } else {
+                ASSERT(variant.kind() == PutByIdVariant::Replace);
+                newSet.add(variant.oldStructure());
             }
-            ASSERT(variant.kind() == PutByIdVariant::Transition);
-            if (value.m_currentKnownStructure.contains(variant.oldStructure()))
-                newSet.addAll(variant.newStructure());
         }
         
-        // Use filter(value, set) as a way of setting the structure set. This works because
-        // we would have already made the set be TOP before this. Filtering top is another 
-        // way of setting.
-        filter(node->child1(), newSet);
+        filter(node->child1(), oldSet);
+        observeTransitions(clobberLimit, transitions);
+        forNode(node->child1()).set(m_graph, newSet);
         break;
     }
     
@@ -1785,7 +1809,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case PutByIdFlush:
     case PutByIdDirect:
         node->setCanExit(true);
-        if (Structure* structure = forNode(node->child1()).bestProvenStructure()) {
+        // This use of onlyStructure() should be replaced by giving PutByIdStatus the ability
+        // to compute things based on a StructureSet, and then to factor ByteCodeParser's
+        // ability to generate code based on a PutByIdStatus out of ByteCodeParser so that
+        // ConstantFoldingPhase can use it.
+        // https://bugs.webkit.org/show_bug.cgi?id=133229
+        if (Structure* structure = forNode(node->child1()).m_structure.onlyStructure()) {
             PutByIdStatus status = PutByIdStatus::computeFor(
                 m_graph.m_vm,
                 m_graph.globalObjectFor(node->origin.semantic),
@@ -1796,13 +1825,13 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
                 if (status[0].kind() == PutByIdVariant::Replace) {
                     filter(node->child1(), structure);
                     m_state.setFoundConstants(true);
-                    m_state.setHaveStructures(true);
                     break;
                 }
-                if (status[0].kind() == PutByIdVariant::Transition) {
+                if (status[0].kind() == PutByIdVariant::Transition
+                    && structure->transitionWatchpointSetHasBeenInvalidated()) {
+                    m_graph.watchpoints().consider(status[0].newStructure());
                     clobberStructures(clobberLimit);
                     forNode(node->child1()).set(m_graph, status[0].newStructure());
-                    m_state.setHaveStructures(true);
                     m_state.setFoundConstants(true);
                     break;
                 }
@@ -1849,7 +1878,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         
     case Upsilon: {
         m_state.createValueForNode(node->phi());
-        AbstractValue& value = forNode(node->child1());
+        AbstractValue value = forNode(node->child1());
         forNode(node) = value;
         forNode(node->phi()) = value;
         break;
@@ -1873,6 +1902,8 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         
     case InvalidationPoint:
         node->setCanExit(true);
+        forAllValues(clobberLimit, AbstractValue::observeInvalidationPointFor);
+        m_state.setStructureClobberState(StructuresAreWatched);
         break;
 
     case CheckWatchdogTimer:
@@ -1955,6 +1986,7 @@ void AbstractInterpreter<AbstractStateType>::clobberWorld(
 template<typename AbstractStateType>
 void AbstractInterpreter<AbstractStateType>::clobberCapturedVars(const CodeOrigin& codeOrigin)
 {
+    SamplingRegion samplingRegion("DFG AI Clobber Captured Vars");
     if (codeOrigin.inlineCallFrame) {
         const BitVector& capturedVars = codeOrigin.inlineCallFrame->capturedVars;
         for (size_t i = capturedVars.size(); i--;) {
@@ -1976,40 +2008,80 @@ void AbstractInterpreter<AbstractStateType>::clobberCapturedVars(const CodeOrigi
 }
 
 template<typename AbstractStateType>
-void AbstractInterpreter<AbstractStateType>::clobberStructures(unsigned clobberLimit)
+template<typename Functor>
+void AbstractInterpreter<AbstractStateType>::forAllValues(
+    unsigned clobberLimit, Functor& functor)
 {
-    if (!m_state.haveStructures())
-        return;
+    SamplingRegion samplingRegion("DFG AI For All Values");
     if (clobberLimit >= m_state.block()->size())
         clobberLimit = m_state.block()->size();
     else
         clobberLimit++;
     ASSERT(clobberLimit <= m_state.block()->size());
     for (size_t i = clobberLimit; i--;)
-        forNode(m_state.block()->at(i)).clobberStructures();
+        functor(forNode(m_state.block()->at(i)));
     if (m_graph.m_form == SSA) {
         HashSet<Node*>::iterator iter = m_state.block()->ssa->liveAtHead.begin();
         HashSet<Node*>::iterator end = m_state.block()->ssa->liveAtHead.end();
         for (; iter != end; ++iter)
-            forNode(*iter).clobberStructures();
+            functor(forNode(*iter));
     }
     for (size_t i = m_state.variables().numberOfArguments(); i--;)
-        m_state.variables().argument(i).clobberStructures();
+        functor(m_state.variables().argument(i));
     for (size_t i = m_state.variables().numberOfLocals(); i--;)
-        m_state.variables().local(i).clobberStructures();
-    m_state.setHaveStructures(true);
+        functor(m_state.variables().local(i));
+}
+
+template<typename AbstractStateType>
+void AbstractInterpreter<AbstractStateType>::clobberStructures(unsigned clobberLimit)
+{
+    SamplingRegion samplingRegion("DFG AI Clobber Structures");
+    forAllValues(clobberLimit, AbstractValue::clobberStructuresFor);
+    setDidClobber();
+}
+
+template<typename AbstractStateType>
+void AbstractInterpreter<AbstractStateType>::observeTransition(
+    unsigned clobberLimit, Structure* from, Structure* to)
+{
+    AbstractValue::TransitionObserver transitionObserver(from, to);
+    forAllValues(clobberLimit, transitionObserver);
+    setDidClobber();
+}
+
+template<typename AbstractStateType>
+void AbstractInterpreter<AbstractStateType>::observeTransitions(
+    unsigned clobberLimit, const TransitionVector& vector)
+{
+    AbstractValue::TransitionsObserver transitionsObserver(vector);
+    forAllValues(clobberLimit, transitionsObserver);
+    setDidClobber();
+}
+
+template<typename AbstractStateType>
+void AbstractInterpreter<AbstractStateType>::setDidClobber()
+{
     m_state.setDidClobber(true);
+    m_state.setStructureClobberState(StructuresAreClobbered);
+}
+
+template<typename AbstractStateType>
+void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out) const
+{
+    const_cast<AbstractInterpreter<AbstractStateType>*>(this)->dump(out);
 }
 
 template<typename AbstractStateType>
 void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out)
 {
     CommaPrinter comma(" ");
+    HashSet<Node*> seen;
     if (m_graph.m_form == SSA) {
         HashSet<Node*>::iterator iter = m_state.block()->ssa->liveAtHead.begin();
         HashSet<Node*>::iterator end = m_state.block()->ssa->liveAtHead.end();
         for (; iter != end; ++iter) {
             Node* node = *iter;
+            seen.add(node);
             AbstractValue& value = forNode(node);
             if (value.isClear())
                 continue;
@@ -2018,11 +2090,25 @@ void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out)
     }
     for (size_t i = 0; i < m_state.block()->size(); ++i) {
         Node* node = m_state.block()->at(i);
+        seen.add(node);
         AbstractValue& value = forNode(node);
         if (value.isClear())
             continue;
         out.print(comma, node, ":", value);
     }
+    if (m_graph.m_form == SSA) {
+        HashSet<Node*>::iterator iter = m_state.block()->ssa->liveAtTail.begin();
+        HashSet<Node*>::iterator end = m_state.block()->ssa->liveAtTail.end();
+        for (; iter != end; ++iter) {
+            Node* node = *iter;
+            if (seen.contains(node))
+                continue;
+            AbstractValue& value = forNode(node);
+            if (value.isClear())
+                continue;
+            out.print(comma, node, ":", value);
+        }
+    }
 }
 
 template<typename AbstractStateType>
index d39ca87..b141206 100644 (file)
 
 namespace JSC { namespace DFG {
 
+void AbstractValue::observeTransitions(const TransitionVector& vector)
+{
+    if (m_type & SpecCell) {
+        m_structure.observeTransitions(vector);
+        ArrayModes newModes = 0;
+        for (unsigned i = vector.size(); i--;) {
+            if (m_arrayModes & asArrayModes(vector[i].previous->indexingType()))
+                newModes |= asArrayModes(vector[i].next->indexingType());
+        }
+        m_arrayModes |= newModes;
+    }
+    checkConsistency();
+}
+
 void AbstractValue::setMostSpecific(Graph& graph, JSValue value)
 {
     if (!!value && value.isCell()) {
         Structure* structure = value.asCell()->structure();
-        m_currentKnownStructure = structure;
-        setFuturePossibleStructure(graph, structure);
+        graph.watchpoints().consider(structure);
+        m_structure = structure;
         m_arrayModes = asArrayModes(structure->indexingType());
     } else {
-        m_currentKnownStructure.clear();
-        m_futurePossibleStructure.clear();
+        m_structure.clear();
         m_arrayModes = 0;
     }
         
@@ -50,19 +63,30 @@ void AbstractValue::setMostSpecific(Graph& graph, JSValue value)
     m_value = value;
         
     checkConsistency();
+    assertIsWatched(graph);
 }
 
-void AbstractValue::set(Graph& graph, JSValue value)
+void AbstractValue::set(Graph& graph, JSValue value, StructureClobberState clobberState)
 {
     if (!!value && value.isCell()) {
-        m_currentKnownStructure.makeTop();
         Structure* structure = value.asCell()->structure();
-        setFuturePossibleStructure(graph, structure);
-        m_arrayModes = asArrayModes(structure->indexingType());
-        clobberArrayModes();
+        if (graph.watchpoints().consider(structure)) {
+            // We should be able to assume that the watchpoint for this has already been set.
+            // But we can't because our view of what structure a value has keeps changing. That's
+            // why we call consider().
+            // https://bugs.webkit.org/show_bug.cgi?id=133426
+            m_structure = structure;
+            if (clobberState == StructuresAreClobbered) {
+                m_arrayModes = ALL_ARRAY_MODES;
+                m_structure.clobber();
+            } else
+                m_arrayModes = asArrayModes(structure->indexingType());
+        } else {
+            m_structure.makeTop();
+            m_arrayModes = ALL_ARRAY_MODES;
+        }
     } else {
-        m_currentKnownStructure.clear();
-        m_futurePossibleStructure.clear();
+        m_structure.clear();
         m_arrayModes = 0;
     }
     
@@ -70,17 +94,29 @@ void AbstractValue::set(Graph& graph, JSValue value)
     m_value = value;
     
     checkConsistency();
+    assertIsWatched(graph);
 }
 
 void AbstractValue::set(Graph& graph, Structure* structure)
 {
-    m_currentKnownStructure = structure;
-    setFuturePossibleStructure(graph, structure);
+    m_structure = structure;
     m_arrayModes = asArrayModes(structure->indexingType());
     m_type = speculationFromStructure(structure);
     m_value = JSValue();
     
     checkConsistency();
+    assertIsWatched(graph);
+}
+
+void AbstractValue::set(Graph& graph, const StructureSet& set)
+{
+    m_structure = set;
+    m_arrayModes = set.arrayModesFromStructures();
+    m_type = set.speculationFromStructures();
+    m_value = JSValue();
+    
+    checkConsistency();
+    assertIsWatched(graph);
 }
 
 void AbstractValue::fixTypeForRepresentation(NodeFlags representation)
@@ -141,21 +177,18 @@ FiltrationResult AbstractValue::filter(Graph& graph, const StructureSet& other)
     
     m_type &= other.speculationFromStructures();
     m_arrayModes &= other.arrayModesFromStructures();
-    m_currentKnownStructure.filter(other);
+    m_structure.filter(other);
     
     // It's possible that prior to the above two statements we had (Foo, TOP), where
     // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that
     // case, we will now have (None, [someStructure]). In general, we need to make
     // sure that new information gleaned from the SpeculatedType needs to be fed back
     // into the information gleaned from the StructureSet.
-    m_currentKnownStructure.filter(m_type);
+    m_structure.filter(m_type);
     
-    if (m_currentKnownStructure.hasSingleton())
-        setFuturePossibleStructure(graph, m_currentKnownStructure.singleton());
-        
     filterArrayModesByType();
     filterValueByType();
-    return normalizeClarity();
+    return normalizeClarity(graph);
 }
 
 FiltrationResult AbstractValue::filterArrayModes(ArrayModes arrayModes)
@@ -175,14 +208,26 @@ FiltrationResult AbstractValue::filter(SpeculatedType type)
     if ((m_type & type) == m_type)
         return FiltrationOK;
     
+    // Fast path for the case that we don't even have a cell.
+    if (!(m_type & SpecCell)) {
+        m_type &= type;
+        FiltrationResult result;
+        if (m_type == SpecNone) {
+            clear();
+            result = Contradiction;
+        } else
+            result = FiltrationOK;
+        checkConsistency();
+        return result;
+    }
+    
     m_type &= type;
     
     // It's possible that prior to this filter() call we had, say, (Final, TOP), and
     // the passed type is Array. At this point we'll have (None, TOP). The best way
     // to ensure that the structure filtering does the right thing is to filter on
     // the new type (None) rather than the one passed (Array).
-    m_currentKnownStructure.filter(m_type);
-    m_futurePossibleStructure.filter(m_type);
+    m_structure.filter(type);
     filterArrayModesByType();
     filterValueByType();
     return normalizeClarity();
@@ -196,15 +241,6 @@ FiltrationResult AbstractValue::filterByValue(JSValue value)
     return result;
 }
 
-void AbstractValue::setFuturePossibleStructure(Graph& graph, Structure* structure)
-{
-    ASSERT(structure);
-    if (graph.watchpoints().isStillValid(structure->transitionWatchpointSet()))
-        m_futurePossibleStructure = structure;
-    else
-        m_futurePossibleStructure.makeTop();
-}
-
 void AbstractValue::filterValueByType()
 {
     // We could go further, and ensure that if the futurePossibleStructure contravenes
@@ -250,8 +286,7 @@ bool AbstractValue::shouldBeClear() const
         return true;
     
     if (!(m_type & ~SpecCell)
-        && (!m_arrayModes
-            || m_currentKnownStructure.isClear()))
+        && (!m_arrayModes || m_structure.isClear()))
         return true;
     
     return false;
@@ -275,12 +310,18 @@ FiltrationResult AbstractValue::normalizeClarity()
     return result;
 }
 
+FiltrationResult AbstractValue::normalizeClarity(Graph& graph)
+{
+    FiltrationResult result = normalizeClarity();
+    assertIsWatched(graph);
+    return result;
+}
+
 #if !ASSERT_DISABLED
 void AbstractValue::checkConsistency() const
 {
     if (!(m_type & SpecCell)) {
-        ASSERT(m_currentKnownStructure.isClear());
-        ASSERT(m_futurePossibleStructure.isClear());
+        ASSERT(m_structure.isClear());
         ASSERT(!m_arrayModes);
     }
     
@@ -301,6 +342,11 @@ void AbstractValue::checkConsistency() const
     // we don't want to get pedantic about this as it would only increase the computational
     // complexity of the code.
 }
+
+void AbstractValue::assertIsWatched(Graph& graph) const
+{
+    m_structure.assertIsWatched(graph);
+}
 #endif
 
 void AbstractValue::dump(PrintStream& out) const
@@ -314,8 +360,7 @@ void AbstractValue::dumpInContext(PrintStream& out, DumpContext* context) const
     if (m_type & SpecCell) {
         out.print(
             ", ", ArrayModesDump(m_arrayModes), ", ",
-            inContext(m_currentKnownStructure, context), ", ",
-            inContext(m_futurePossibleStructure, context));
+            inContext(m_structure, context));
     }
     if (!!m_value)
         out.print(", ", inContext(m_value, context));
index 14363df..f71f073 100644 (file)
@@ -32,6 +32,7 @@
 #include "DFGFiltrationResult.h"
 #include "DFGNodeFlags.h"
 #include "DFGStructureAbstractValue.h"
+#include "DFGStructureClobberState.h"
 #include "JSCell.h"
 #include "SpeculatedType.h"
 #include "DumpContext.h"
@@ -53,8 +54,7 @@ struct AbstractValue {
     {
         m_type = SpecNone;
         m_arrayModes = 0;
-        m_currentKnownStructure.clear();
-        m_futurePossibleStructure.clear();
+        m_structure.clear();
         m_value = JSValue();
         checkConsistency();
     }
@@ -75,15 +75,74 @@ struct AbstractValue {
     void clobberStructures()
     {
         if (m_type & SpecCell) {
-            m_currentKnownStructure.makeTop();
+            m_structure.clobber();
             clobberArrayModes();
         } else {
-            ASSERT(m_currentKnownStructure.isClear());
+            ASSERT(m_structure.isClear());
             ASSERT(!m_arrayModes);
         }
         checkConsistency();
     }
+    
+    static void clobberStructuresFor(AbstractValue& value)
+    {
+        value.clobberStructures();
+    }
+    
+    void observeInvalidationPoint()
+    {
+        m_structure.observeInvalidationPoint();
+        checkConsistency();
+    }
+    
+    static void observeInvalidationPointFor(AbstractValue& value)
+    {
+        value.observeInvalidationPoint();
+    }
+    
+    void observeTransition(Structure* from, Structure* to)
+    {
+        if (m_type & SpecCell) {
+            m_structure.observeTransition(from, to);
+            observeIndexingTypeTransition(from->indexingType(), to->indexingType());
+        }
+        checkConsistency();
+    }
+    
+    void observeTransitions(const TransitionVector& vector);
+    
+    class TransitionObserver {
+    public:
+        TransitionObserver(Structure* from, Structure* to)
+            : m_from(from)
+            , m_to(to)
+        {
+        }
+        
+        void operator()(AbstractValue& value)
+        {
+            value.observeTransition(m_from, m_to);
+        }
+    private:
+        Structure* m_from;
+        Structure* m_to;
+    };
+    
+    class TransitionsObserver {
+    public:
+        TransitionsObserver(const TransitionVector& vector)
+            : m_vector(vector)
+        {
+        }
         
+        void operator()(AbstractValue& value)
+        {
+            value.observeTransitions(m_vector);
+        }
+    private:
+        const TransitionVector& m_vector;
+    };
+    
     void clobberValue()
     {
         m_value = JSValue();
@@ -91,7 +150,10 @@ struct AbstractValue {
     
     bool isHeapTop() const
     {
-        return (m_type | SpecHeapTop) == m_type && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop();
+        return (m_type | SpecHeapTop) == m_type
+            && m_structure.isTop()
+            && m_arrayModes == ALL_ARRAY_MODES
+            && !m_value;
     }
     
     bool valueIsTop() const
@@ -112,18 +174,17 @@ struct AbstractValue {
     }
     
     void setMostSpecific(Graph&, JSValue);
-    void set(Graph&, JSValue);
+    void set(Graph&, JSValue, StructureClobberState);
     void set(Graph&, Structure*);
+    void set(Graph&, const StructureSet&);
     
     void setType(SpeculatedType type)
     {
         if (type & SpecCell) {
-            m_currentKnownStructure.makeTop();
-            m_futurePossibleStructure.makeTop();
+            m_structure.makeTop();
             m_arrayModes = ALL_ARRAY_MODES;
         } else {
-            m_currentKnownStructure.clear();
-            m_futurePossibleStructure.clear();
+            m_structure.clear();
             m_arrayModes = 0;
         }
         m_type = type;
@@ -138,8 +199,7 @@ struct AbstractValue {
     {
         return m_type == other.m_type
             && m_arrayModes == other.m_arrayModes
-            && m_currentKnownStructure == other.m_currentKnownStructure
-            && m_futurePossibleStructure == other.m_futurePossibleStructure
+            && m_structure == other.m_structure
             && m_value == other.m_value;
     }
     bool operator!=(const AbstractValue& other) const
@@ -162,8 +222,7 @@ struct AbstractValue {
         } else {
             result |= mergeSpeculation(m_type, other.m_type);
             result |= mergeArrayModes(m_arrayModes, other.m_arrayModes);
-            result |= m_currentKnownStructure.addAll(other.m_currentKnownStructure);
-            result |= m_futurePossibleStructure.addAll(other.m_futurePossibleStructure);
+            result |= m_structure.merge(other.m_structure);
             if (m_value != other.m_value) {
                 result |= !!m_value;
                 m_value = JSValue();
@@ -179,8 +238,7 @@ struct AbstractValue {
         mergeSpeculation(m_type, type);
         
         if (type & SpecCell) {
-            m_currentKnownStructure.makeTop();
-            m_futurePossibleStructure.makeTop();
+            m_structure.makeTop();
             m_arrayModes = ALL_ARRAY_MODES;
         }
         m_value = JSValue();
@@ -225,75 +283,30 @@ struct AbstractValue {
         if (!!value && value.isCell()) {
             ASSERT(m_type & SpecCell);
             Structure* structure = value.asCell()->structure();
-            return m_currentKnownStructure.contains(structure)
-                && m_futurePossibleStructure.contains(structure)
+            return m_structure.contains(structure)
                 && (m_arrayModes & asArrayModes(structure->indexingType()));
         }
         
         return true;
     }
     
-    Structure* bestProvenStructure() const
-    {
-        if (m_currentKnownStructure.hasSingleton())
-            return m_currentKnownStructure.singleton();
-        if (m_futurePossibleStructure.hasSingleton())
-            return m_futurePossibleStructure.singleton();
-        return 0;
-    }
-    
     bool hasClobberableState() const
     {
-        return m_currentKnownStructure.isNeitherClearNorTop()
+        return m_structure.isNeitherClearNorTop()
             || !arrayModesAreClearOrTop(m_arrayModes);
     }
     
 #if ASSERT_DISABLED
     void checkConsistency() const { }
+    void assertIsWatched(Graph&) const { }
 #else
     void checkConsistency() const;
+    void assertIsWatched(Graph&) const;
 #endif
     
     void dumpInContext(PrintStream&, DumpContext*) const;
     void dump(PrintStream&) const;
     
-    // A great way to think about the difference between m_currentKnownStructure and
-    // m_futurePossibleStructure is to consider these four examples:
-    //
-    // 1) x = foo();
-    //
-    //    In this case x's m_currentKnownStructure and m_futurePossibleStructure will
-    //    both be TOP, since we don't know anything about x for sure, yet.
-    //
-    // 2) x = foo();
-    //    y = x.f;
-    //
-    //    Where x will later have a new property added to it, 'g'. Because of the
-    //    known but not-yet-executed property addition, x's current structure will
-    //    not be watchpointable; hence we have no way of statically bounding the set
-    //    of possible structures that x may have if a clobbering event happens. So,
-    //    x's m_currentKnownStructure will be whatever structure we check to get
-    //    property 'f', and m_futurePossibleStructure will be TOP.
-    //
-    // 3) x = foo();
-    //    y = x.f;
-    //
-    //    Where x has a terminal structure that is still watchpointable. In this case,
-    //    x's m_currentKnownStructure and m_futurePossibleStructure will both be
-    //    whatever structure we checked for when getting 'f'.
-    //
-    // 4) x = foo();
-    //    y = x.f;
-    //    bar();
-    //
-    //    Where x has a terminal structure that is still watchpointable. In this
-    //    case, m_currentKnownStructure will be TOP because bar() may potentially
-    //    change x's structure and we have no way of proving otherwise, but
-    //    x's m_futurePossibleStructure will be whatever structure we had checked
-    //    when getting property 'f'.
-    
-    // NB. All fields in this struct must have trivial destructors.
-
     // This is a proven constraint on the structures that this value can have right
     // now. The structure of the current value must belong to this set. The set may
     // be TOP, indicating that it is the set of all possible structures, in which
@@ -301,29 +314,12 @@ struct AbstractValue {
     // in which case this value cannot be a cell. This is all subject to change
     // anytime a new value is assigned to this one, anytime there is a control flow
     // merge, or most crucially, anytime a side-effect or structure check happens.
-    // In case of a side-effect, we typically must assume that any value may have
-    // had its structure changed, hence contravening our proof. We make the proof
-    // valid again by switching this to TOP (i.e. claiming that we have proved that
-    // this value may have any structure). Of note is that the proof represented by
-    // this field is not subject to structure transition watchpoints - even if one
-    // fires, we can be sure that this proof is still valid.
-    StructureAbstractValue m_currentKnownStructure;
-    
-    // This is a proven constraint on the structures that this value can have now
-    // or any time in the future subject to the structure transition watchpoints of
-    // all members of this set not having fired. This set is impervious to side-
-    // effects; even if one happens the side-effect can only cause the value to
-    // change to at worst another structure that is also a member of this set. But,
-    // the theorem being proved by this field is predicated upon there not being
-    // any new structure transitions introduced into any members of this set. In
-    // cases where there is no way for us to guard this happening, the set must be
-    // TOP. But in cases where we can guard new structure transitions (all members
-    // of the set have still-valid structure transition watchpoints) then this set
-    // will be finite. Anytime that we make use of the finite nature of this set,
-    // we must first issue a structure transition watchpoint, which will effectively
-    // result in m_currentKnownStructure being filtered according to
-    // m_futurePossibleStructure.
-    StructureAbstractValue m_futurePossibleStructure;
+    // In case of a side-effect, we must assume that any value with a structure that
+    // isn't being watched may have had its structure changed, hence contravening
+    // our proof. In such a case we make the proof valid again by switching this to
+    // TOP (i.e. claiming that we have proved that this value may have any
+    // structure).
+    StructureAbstractValue m_structure;
     
     // This is a proven constraint on the possible types that this value can have
     // now or any time in the future, unless it is reassigned. This field is
@@ -332,11 +328,11 @@ struct AbstractValue {
     // between this field, and the structure fields above, is as follows. The
     // fields above constraint the structures that a cell may have, but they say
     // nothing about whether or not the value is known to be a cell. More formally,
-    // the m_currentKnownStructure is itself an abstract value that consists of the
+    // the m_structure is itself an abstract value that consists of the
     // union of the set of all non-cell values and the set of cell values that have
     // the given structure. This abstract value is then the intersection of the
-    // m_currentKnownStructure and the set of values whose type is m_type. So, for
-    // example if m_type is SpecFinal|SpecInt32 and m_currentKnownStructure is
+    // m_structure and the set of values whose type is m_type. So, for
+    // example if m_type is SpecFinal|SpecInt32 and m_structure is
     // [0x12345] then this abstract value corresponds to the set of all integers
     // unified with the set of all objects with structure 0x12345.
     SpeculatedType m_type;
@@ -364,6 +360,12 @@ private:
         m_arrayModes = ALL_ARRAY_MODES;
     }
     
+    void observeIndexingTypeTransition(IndexingType from, IndexingType to)
+    {
+        if (m_arrayModes & asArrayModes(from))
+            m_arrayModes |= asArrayModes(to);
+    }
+    
     bool validateType(JSValue value) const
     {
         if (isHeapTop())
@@ -391,19 +393,17 @@ private:
     {
         m_type |= top;
         m_arrayModes = ALL_ARRAY_MODES;
-        m_currentKnownStructure.makeTop();
-        m_futurePossibleStructure.makeTop();
+        m_structure.makeTop();
         m_value = JSValue();
         checkConsistency();
     }
     
-    void setFuturePossibleStructure(Graph&, Structure*);
-
     void filterValueByType();
     void filterArrayModesByType();
     
     bool shouldBeClear() const;
     FiltrationResult normalizeClarity();
+    FiltrationResult normalizeClarity(Graph&);
 };
 
 } } // namespace JSC::DFG
index 6e20fb3..09feb94 100644 (file)
@@ -50,7 +50,7 @@ public:
     void* allocate(); // Use placement new to allocate, and avoid using this method.
     void free(T*); // Call this method to delete; never use 'delete' directly.
     
-    void freeAll(); // Only call this if T has a trivial destructor.
+    void freeAll(); // Only call this if you've either freed everything or if T has a trivial destructor.
     void reset(); // Like freeAll(), but also returns all memory to the OS.
     
     unsigned indexOf(const T*);
index 29572b9..a52404e 100644 (file)
@@ -325,7 +325,6 @@ public:
                     break;
                     
                 case CheckStructure:
-                case StructureTransitionWatchpoint:
                 case CheckArray:
                     // We don't care about these because if we get uses of the relevant
                     // variable then we can safely get rid of these, too. This of course
@@ -441,7 +440,6 @@ public:
                 }
                     
                 case CheckStructure:
-                case StructureTransitionWatchpoint:
                 case CheckArray: {
                     // We can just get rid of this node, if it references a phantom argument.
                     if (!isOKToOptimize(node->child1().node()))
index 7391c02..fa1e5e6 100644 (file)
@@ -289,25 +289,48 @@ Structure* ArrayMode::originalArrayStructure(Graph& graph, Node* node) const
 bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value, IndexingType shape) const
 {
     switch (arrayClass()) {
-    case Array::OriginalArray:
-        return value.m_currentKnownStructure.hasSingleton()
-            && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape
-            && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray)
-            && graph.globalObjectFor(node->origin.semantic)->isOriginalArrayStructure(value.m_currentKnownStructure.singleton());
+    case Array::OriginalArray: {
+        if (value.m_structure.isTop())
+            return false;
+        for (unsigned i = value.m_structure.size(); i--;) {
+            Structure* structure = value.m_structure[i];
+            if ((structure->indexingType() & IndexingShapeMask) != shape)
+                return false;
+            if (!(structure->indexingType() & IsArray))
+                return false;
+            if (!graph.globalObjectFor(node->origin.semantic)->isOriginalArrayStructure(structure))
+                return false;
+        }
+        return true;
+    }
         
-    case Array::Array:
+    case Array::Array: {
         if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape | IsArray)))
             return true;
-        return value.m_currentKnownStructure.hasSingleton()
-            && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape
-            && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
+        if (value.m_structure.isTop())
+            return false;
+        for (unsigned i = value.m_structure.size(); i--;) {
+            Structure* structure = value.m_structure[i];
+            if ((structure->indexingType() & IndexingShapeMask) != shape)
+                return false;
+            if (!(structure->indexingType() & IsArray))
+                return false;
+        }
+        return true;
+    }
         
-    default:
+    default: {
         if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape) | asArrayModes(shape | IsArray)))
             return true;
-        return value.m_currentKnownStructure.hasSingleton()
-            && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape;
-    }
+        if (value.m_structure.isTop())
+            return false;
+        for (unsigned i = value.m_structure.size(); i--;) {
+            Structure* structure = value.m_structure[i];
+            if ((structure->indexingType() & IndexingShapeMask) != shape)
+                return false;
+        }
+        return true;
+    } }
 }
 
 bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value) const
@@ -336,23 +359,38 @@ bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value) c
         
     case Array::SlowPutArrayStorage:
         switch (arrayClass()) {
-        case Array::OriginalArray:
+        case Array::OriginalArray: {
             CRASH();
             return false;
+        }
         
-        case Array::Array:
+        case Array::Array: {
             if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
                 return true;
-            return value.m_currentKnownStructure.hasSingleton()
-                && hasAnyArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
-                && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
+            if (value.m_structure.isTop())
+                return false;
+            for (unsigned i = value.m_structure.size(); i--;) {
+                Structure* structure = value.m_structure[i];
+                if (!hasAnyArrayStorage(structure->indexingType()))
+                    return false;
+                if (!(structure->indexingType() & IsArray))
+                    return false;
+            }
+            return true;
+        }
         
-        default:
+        default: {
             if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
                 return true;
-            return value.m_currentKnownStructure.hasSingleton()
-                && hasAnyArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
-        }
+            if (value.m_structure.isTop())
+                return false;
+            for (unsigned i = value.m_structure.size(); i--;) {
+                Structure* structure = value.m_structure[i];
+                if (!hasAnyArrayStorage(structure->indexingType()))
+                    return false;
+            }
+            return true;
+        } }
         
     case Array::Arguments:
         return speculationChecked(value.m_type, SpecArguments);
index 7a872f9..9bf09da 100644 (file)
@@ -54,12 +54,13 @@ public:
     
     bool isValid() { return m_block->cfaDidFinish; }
     
+    StructureClobberState structureClobberState() const { return m_block->cfaStructureClobberStateAtTail; }
+    
     void setDidClobber(bool) { }
+    void setStructureClobberState(StructureClobberState state) { RELEASE_ASSERT(state == m_block->cfaStructureClobberStateAtTail); }
     void setIsValid(bool isValid) { m_block->cfaDidFinish = isValid; }
     void setBranchDirection(BranchDirection) { }
     void setFoundConstants(bool) { }
-    bool haveStructures() const { return true; } // It's always safe to return true.
-    void setHaveStructures(bool) { }
 
 private:
     BasicBlock* m_block;
index 5f3b480..fadf622 100644 (file)
@@ -41,6 +41,8 @@ BasicBlock::BasicBlock(
     , cfaShouldRevisit(false)
     , cfaFoundConstants(false)
     , cfaDidFinish(true)
+    , cfaStructureClobberStateAtHead(StructuresAreWatched)
+    , cfaStructureClobberStateAtTail(StructuresAreWatched)
     , cfaBranchDirection(InvalidBranchDirection)
 #if !ASSERT_DISABLED
     , isLinked(false)
index 19d5487..27f5877 100644 (file)
@@ -33,6 +33,7 @@
 #include "DFGBranchDirection.h"
 #include "DFGFlushedAt.h"
 #include "DFGNode.h"
+#include "DFGStructureClobberState.h"
 #include "Operands.h"
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
@@ -116,6 +117,8 @@ struct BasicBlock : RefCounted<BasicBlock> {
     bool cfaShouldRevisit;
     bool cfaFoundConstants;
     bool cfaDidFinish;
+    StructureClobberState cfaStructureClobberStateAtHead;
+    StructureClobberState cfaStructureClobberStateAtTail;
     BranchDirection cfaBranchDirection;
 #if !ASSERT_DISABLED
     bool isLinked;
index 811c898..cfde4eb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -50,7 +50,7 @@ static inline const char* branchDirectionToString(BranchDirection branchDirectio
 {
     switch (branchDirection) {
     case InvalidBranchDirection:
-        return "Invalid";
+        return "InvalidBranchDirection";
     case TakeTrue:
         return "TakeTrue";
     case TakeFalse:
@@ -81,6 +81,15 @@ static inline bool branchCondition(BranchDirection branchDirection)
 
 } } // namespace JSC::DFG
 
+namespace WTF {
+
+inline void printInternal(PrintStream& out, JSC::DFG::BranchDirection direction)
+{
+    out.print(JSC::DFG::branchDirectionToString(direction));
+}
+
+} // namespace WTF
+
 #endif // ENABLE(DFG_JIT)
 
 #endif // DFGBranchDirection_h
index 059c19a..ecffc42 100644 (file)
@@ -1921,6 +1921,7 @@ Node* ByteCodeParser::handlePutByOffset(Node* base, unsigned identifier, Propert
 Node* ByteCodeParser::emitPrototypeChecks(
     Structure* structure, IntendedStructureChain* chain)
 {
+    ASSERT(structure);
     Node* base = 0;
     m_graph.chains().addLazily(chain);
     Structure* currentStructure = structure;
@@ -1962,7 +1963,7 @@ void ByteCodeParser::handleGetById(
         for (unsigned variantIndex = getByIdStatus.numVariants(); variantIndex--;) {
             if (getByIdStatus[variantIndex].chain()) {
                 emitPrototypeChecks(
-                    getByIdStatus[variantIndex].structureSet().singletonStructure(),
+                    getByIdStatus[variantIndex].structureSet().onlyStructure(),
                     getByIdStatus[variantIndex].chain());
             }
         }
@@ -1988,7 +1989,7 @@ void ByteCodeParser::handleGetById(
     
     if (variant.chain()) {
         base = emitPrototypeChecks(
-            variant.structureSet().singletonStructure(), variant.chain());
+            variant.structureSet().onlyStructure(), variant.chain());
     }
     
     // Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to
@@ -2131,8 +2132,8 @@ void ByteCodeParser::handlePutById(
     ASSERT(variant.oldStructure()->transitionWatchpointSetHasBeenInvalidated());
     
     Node* propertyStorage;
-    StructureTransitionData* transitionData = m_graph.addStructureTransitionData(
-        StructureTransitionData(variant.oldStructure(), variant.newStructure()));
+    Transition* transition = m_graph.m_transitions.add(
+        variant.oldStructure(), variant.newStructure());
 
     if (variant.oldStructure()->outOfLineCapacity()
         != variant.newStructure()->outOfLineCapacity()) {
@@ -2143,10 +2144,10 @@ void ByteCodeParser::handlePutById(
 
         if (!variant.oldStructure()->outOfLineCapacity()) {
             propertyStorage = addToGraph(
-                AllocatePropertyStorage, OpInfo(transitionData), base);
+                AllocatePropertyStorage, OpInfo(transition), base);
         } else {
             propertyStorage = addToGraph(
-                ReallocatePropertyStorage, OpInfo(transitionData),
+                ReallocatePropertyStorage, OpInfo(transition),
                 base, addToGraph(GetButterfly, base));
         }
     } else {
@@ -2156,7 +2157,7 @@ void ByteCodeParser::handlePutById(
             propertyStorage = addToGraph(GetButterfly, base);
     }
 
-    addToGraph(PutStructure, OpInfo(transitionData), base);
+    addToGraph(PutStructure, OpInfo(transition), base);
 
     addToGraph(
         PutByOffset,
@@ -3131,7 +3132,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                     set(VirtualRegister(dst), addToGraph(GetByIdFlush, OpInfo(identifierNumber), OpInfo(prediction), get(VirtualRegister(scope))));
                     break;
                 }
-                Node* base = cellConstantWithStructureCheck(globalObject, status[0].structureSet().singletonStructure());
+                Node* base = cellConstantWithStructureCheck(globalObject, status[0].structureSet().onlyStructure());
                 addToGraph(Phantom, get(VirtualRegister(scope)));
                 if (JSValue specificValue = status[0].specificValue())
                     set(VirtualRegister(dst), cellConstant(specificValue.asCell()));
index 5f69de1..46b6021 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -92,8 +92,11 @@ private:
         if (m_verbose)
             dataLog("   Block ", *block, ":\n");
         m_state.beginBasicBlock(block);
-        if (m_verbose)
+        if (m_verbose) {
             dataLog("      head vars: ", block->valuesAtHead, "\n");
+            if (m_graph.m_form == SSA)
+                dataLog("      head regs: ", mapDump(block->ssa->valuesAtHead), "\n");
+        }
         for (unsigned i = 0; i < block->size(); ++i) {
             if (m_verbose) {
                 Node* node = block->at(i);
@@ -102,10 +105,8 @@ private:
                 if (!safeToExecute(m_state, m_graph, node))
                     dataLog("(UNSAFE) ");
                 
-                m_interpreter.dump(WTF::dataFile());
+                dataLog(m_state.variables(), " ", m_interpreter);
                 
-                if (m_state.haveStructures())
-                    dataLog(" (Have Structures)");
                 dataLogF("\n");
             }
             if (!m_interpreter.execute(i)) {
@@ -121,8 +122,11 @@ private:
         }
         m_changed |= m_state.endBasicBlock(MergeToSuccessors);
         
-        if (m_verbose)
+        if (m_verbose) {
             dataLog("      tail vars: ", block->valuesAtTail, "\n");
+            if (m_graph.m_form == SSA)
+                dataLog("      head regs: ", mapDump(block->ssa->valuesAtTail), "\n");
+        }
     }
     
     void performForwardCFA()
index 635ef21..5f0670e 100644 (file)
@@ -460,17 +460,11 @@ private:
                     return true;
                 break;
                 
-            case StructureTransitionWatchpoint:
-                if (node->child1() == child1
-                    && structureSet.contains(node->structure()))
-                    return true;
-                break;
-                
             case PutStructure:
                 if (node->child1() == child1
-                    && structureSet.contains(node->structureTransitionData().newStructure))
+                    && structureSet.contains(node->transition()->next))
                     return true;
-                if (structureSet.contains(node->structureTransitionData().previousStructure))
+                if (structureSet.contains(node->transition()->previous))
                     return false;
                 break;
                 
@@ -519,12 +513,12 @@ private:
             switch (node->op()) {
             case CheckStructure:
                 if (node->child1() == child1
-                    && node->structureSet().containsOnly(structure))
+                    && node->structureSet().isSubsetOf(StructureSet(structure)))
                     return true;
                 break;
                 
             case PutStructure:
-                ASSERT(node->structureTransitionData().previousStructure != structure);
+                ASSERT(node->transition()->previous != structure);
                 break;
                 
             case PutByOffset:
@@ -547,11 +541,6 @@ private:
                 }
                 return false;
                 
-            case StructureTransitionWatchpoint:
-                if (node->structure() == structure && node->child1() == child1)
-                    return true;
-                break;
-                
             case Arrayify:
             case ArrayifyToStructure:
                 // We could check if the arrayification could affect our structures.
@@ -1423,13 +1412,6 @@ private:
                 eliminate();
             break;
             
-        case StructureTransitionWatchpoint:
-            if (cseMode == StoreElimination)
-                break;
-            if (structureTransitionWatchpointElimination(node->structure(), node->child1().node()))
-                eliminate();
-            break;
-            
         case PutStructure:
             if (cseMode == NormalCSE)
                 break;
index 17a59dd..ed967a5 100644 (file)
 namespace JSC { namespace DFG {
 
 template<typename ReadFunctor, typename WriteFunctor>
-void clobberizeForAllocation(ReadFunctor& read, WriteFunctor& write)
-{
-    read(GCState);
-    read(BarrierState);
-    write(GCState);
-    write(BarrierState);
-}
-
-template<typename ReadFunctor, typename WriteFunctor>
 void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write)
 {
     // Some notes:
@@ -133,6 +124,7 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
     case Int52Rep:
     case BooleanToNumber:
     case FiatInt52:
+    case MakeRope:
         return;
         
     case MovHint:
@@ -158,6 +150,8 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
     case Breakpoint:
     case ProfileWillCall:
     case ProfileDidCall:
+    case StoreBarrier:
+    case StoreBarrierWithNullCheck:
         write(SideState);
         return;
         
@@ -174,7 +168,8 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
 
     case CreateActivation:
     case CreateArguments:
-        clobberizeForAllocation(read, write);
+        read(HeapObjectCount);
+        write(HeapObjectCount);
         write(SideState);
         write(Watchpoint_fire);
         return;
@@ -186,7 +181,8 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
     case ToThis:
     case CreateThis:
         read(MiscFields);
-        clobberizeForAllocation(read, write);
+        read(HeapObjectCount);
+        write(HeapObjectCount);
         return;
 
     case VarInjectionWatchpoint:
@@ -424,7 +420,6 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
     }
         
     case CheckStructure:
-    case StructureTransitionWatchpoint:
     case InstanceOf:
         read(JSCell_structureID);
         return;
@@ -453,13 +448,11 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
         
     case AllocatePropertyStorage:
         write(JSObject_butterfly);
-        clobberizeForAllocation(read, write);
         return;
         
     case ReallocatePropertyStorage:
         read(JSObject_butterfly);
         write(JSObject_butterfly);
-        clobberizeForAllocation(read, write);
         return;
         
     case GetButterfly:
@@ -475,7 +468,6 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
         write(JSCell_indexingType);
         write(JSObject_butterfly);
         write(Watchpoint_fire);
-        clobberizeForAllocation(read, write);
         return;
         
     case GetIndexedPropertyStorage:
@@ -508,10 +500,8 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
         write(AbstractHeap(NamedProperties, node->multiPutByOffsetData().identifierNumber));
         if (node->multiPutByOffsetData().writesStructures())
             write(JSCell_structureID);
-        if (node->multiPutByOffsetData().reallocatesStorage()) {
+        if (node->multiPutByOffsetData().reallocatesStorage())
             write(JSObject_butterfly);
-            clobberizeForAllocation(read, write);
-        }
         return;
         
     case PutByOffset:
@@ -577,15 +567,16 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
     case NewArrayBuffer:
     case NewRegexp:
     case NewStringObject:
-    case MakeRope:
     case NewFunctionNoCheck:
     case NewFunction:
     case NewFunctionExpression:
-        clobberizeForAllocation(read, write);
+        read(HeapObjectCount);
+        write(HeapObjectCount);
         return;
         
     case NewTypedArray:
-        clobberizeForAllocation(read, write);
+        read(HeapObjectCount);
+        write(HeapObjectCount);
         switch (node->child1().useKind()) {
         case Int32Use:
             return;
@@ -663,7 +654,8 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
 
     case ThrowReferenceError:
         write(SideState);
-        clobberizeForAllocation(read, write);
+        read(HeapObjectCount);
+        write(HeapObjectCount);
         return;
         
     case CountExecution:
@@ -671,12 +663,6 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
         read(InternalState);
         write(InternalState);
         return;
-
-    case StoreBarrier:
-    case StoreBarrierWithNullCheck:
-        read(BarrierState);
-        write(BarrierState);
-        return;
         
     case LastNodeType:
         RELEASE_ASSERT_NOT_REACHED();
index 09ac340..a11d7b8 100644 (file)
 
 namespace JSC { namespace DFG {
 
+static unsigned crashLock;
+
 void startCrashing()
 {
 #if ENABLE(COMPARE_AND_SWAP)
-    static unsigned lock;
-    while (!WTF::weakCompareAndSwap(&lock, 0, 1))
+    while (!WTF::weakCompareAndSwap(&crashLock, 0, 1))
         std::this_thread::yield();
+#else
+    crashLock = 1;
 #endif
 }
 
+bool isCrashing()
+{
+    return !!crashLock;
+}
+
 } } // namespace JSC::DFG
 
 namespace WTF {
index dbe7ca2..5b08fe4 100644 (file)
@@ -259,6 +259,8 @@ bool checkAndSet(T& left, U right)
 // when you're forcing a crash with diagnostics.
 void startCrashing();
 
+JS_EXPORT_PRIVATE bool isCrashing();
+
 } } // namespace JSC::DFG
 
 namespace WTF {
index ad4d09d..d78c0f2 100644 (file)
@@ -41,8 +41,8 @@ void CommonData::notifyCompilingStructureTransition(Plan& plan, CodeBlock* codeB
     plan.transitions.addLazily(
         codeBlock,
         node->origin.semantic.codeOriginOwner(),
-        node->structureTransitionData().previousStructure,
-        node->structureTransitionData().newStructure);
+        node->transition()->previous,
+        node->transition()->next);
 }
 
 unsigned CommonData::addCodeOrigin(CodeOrigin codeOrigin)
index d0059a8..39cd8bf 100644 (file)
@@ -104,27 +104,12 @@ private:
                     set = node->structure();
                 else
                     set = node->structureSet();
-                if (value.m_currentKnownStructure.isSubsetOf(set)) {
+                if (value.m_structure.isSubsetOf(set)) {
                     m_interpreter.execute(indexInBlock); // Catch the fact that we may filter on cell.
                     node->convertToPhantom();
                     eliminated = true;
                     break;
                 }
-                StructureAbstractValue& structureValue = value.m_futurePossibleStructure;
-                if (structureValue.isSubsetOf(set)
-                    && structureValue.hasSingleton()) {
-                    Structure* structure = structureValue.singleton();
-                    m_interpreter.execute(indexInBlock); // Catch the fact that we may filter on cell.
-                    AdjacencyList children = node->children;
-                    children.removeEdge(0);
-                    if (!!children.child1())
-                        m_insertionSet.insertNode(indexInBlock, SpecNone, Phantom, node->origin, children);
-                    node->children.setChild2(Edge());
-                    node->children.setChild3(Edge());
-                    node->convertToStructureTransitionWatchpoint(structure);
-                    eliminated = true;
-                    break;
-                }
                 break;
             }
                 
@@ -163,7 +148,7 @@ private:
                 Node* child = childEdge.node();
                 MultiGetByOffsetData& data = node->multiGetByOffsetData();
 
-                Structure* structure = m_state.forNode(child).bestProvenStructure();
+                Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
                 if (!structure)
                     break;
                 
@@ -187,7 +172,7 @@ private:
                 Node* child = childEdge.node();
                 MultiPutByOffsetData& data = node->multiPutByOffsetData();
 
-                Structure* structure = m_state.forNode(child).bestProvenStructure();
+                Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
                 if (!structure)
                     break;
                 
@@ -212,7 +197,7 @@ private:
                 if (childEdge.useKind() != CellUse)
                     break;
                 
-                Structure* structure = m_state.forNode(child).bestProvenStructure();
+                Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
                 if (!structure)
                     break;
 
@@ -239,7 +224,7 @@ private:
                 
                 ASSERT(childEdge.useKind() == CellUse);
                 
-                Structure* structure = m_state.forNode(child).bestProvenStructure();
+                Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
                 if (!structure)
                     break;
                 
@@ -305,7 +290,7 @@ private:
             // then we refuse to fold.
             AbstractValue oldValue = m_state.forNode(node);
             AbstractValue constantValue;
-            constantValue.set(m_graph, value);
+            constantValue.set(m_graph, value, m_state.structureClobberState());
             constantValue.fixTypeForRepresentation(node);
             if (oldValue.merge(constantValue))
                 continue;
@@ -336,22 +321,17 @@ private:
         Edge childEdge = node->child1();
         Node* child = childEdge.node();
 
-        bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton();
         bool needsCellCheck = m_state.forNode(child).m_type & ~SpecCell;
         
         ASSERT(!variant.chain());
-        ASSERT(variant.structureSet().contains(structure));
+        ASSERT_UNUSED(structure, variant.structureSet().contains(structure));
         
         // Now before we do anything else, push the CFA forward over the GetById
         // and make sure we signal to the loop that it should continue and not
         // do any eliminations.
         m_interpreter.execute(indexInBlock);
         
-        if (needsWatchpoint) {
-            m_insertionSet.insertNode(
-                indexInBlock, SpecNone, StructureTransitionWatchpoint, origin,
-                OpInfo(structure), childEdge);
-        } else if (needsCellCheck) {
+        if (needsCellCheck) {
             m_insertionSet.insertNode(
                 indexInBlock, SpecNone, Phantom, origin, childEdge);
         }
@@ -388,7 +368,6 @@ private:
 
         ASSERT(variant.oldStructure() == structure);
         
-        bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton();
         bool needsCellCheck = m_state.forNode(child).m_type & ~SpecCell;
         
         // Now before we do anything else, push the CFA forward over the PutById
@@ -396,21 +375,16 @@ private:
         // do any eliminations.
         m_interpreter.execute(indexInBlock);
 
-        if (needsWatchpoint) {
-            m_insertionSet.insertNode(
-                indexInBlock, SpecNone, StructureTransitionWatchpoint, origin,
-                OpInfo(structure), childEdge);
-        } else if (needsCellCheck) {
+        if (needsCellCheck) {
             m_insertionSet.insertNode(
                 indexInBlock, SpecNone, Phantom, origin, childEdge);
         }
 
         childEdge.setUseKind(KnownCellUse);
 
-        StructureTransitionData* transitionData = 0;
+        Transition* transition = 0;
         if (variant.kind() == PutByIdVariant::Transition) {
-            transitionData = m_graph.addStructureTransitionData(
-                StructureTransitionData(structure, variant.newStructure()));
+            transition = m_graph.m_transitions.add(structure, variant.newStructure());
 
             if (node->op() == PutById) {
                 if (!structure->storedPrototype().isNull()) {
@@ -446,7 +420,7 @@ private:
             ASSERT(!isInlineOffset(variant.offset()));
             Node* allocatePropertyStorage = m_insertionSet.insertNode(
                 indexInBlock, SpecNone, AllocatePropertyStorage,
-                origin, OpInfo(transitionData), childEdge);
+                origin, OpInfo(transition), childEdge);
             m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node->child1().node(), KnownCellUse));
             propertyStorage = Edge(allocatePropertyStorage);
         } else {
@@ -456,7 +430,7 @@ private:
 
             Node* reallocatePropertyStorage = m_insertionSet.insertNode(
                 indexInBlock, SpecNone, ReallocatePropertyStorage, origin,
-                OpInfo(transitionData), childEdge,
+                OpInfo(transition), childEdge,
                 Edge(m_insertionSet.insertNode(
                     indexInBlock, SpecNone, GetButterfly, origin, childEdge)));
             m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node->child1().node(), KnownCellUse));
@@ -464,7 +438,7 @@ private:
         }
 
         if (variant.kind() == PutByIdVariant::Transition) {
-            Node* putStructure = m_graph.addNode(SpecNone, PutStructure, origin, OpInfo(transitionData), childEdge);
+            Node* putStructure = m_graph.addNode(SpecNone, PutStructure, origin, OpInfo(transition), childEdge);
             m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node->child1().node(), KnownCellUse));
             m_insertionSet.insert(indexInBlock, putStructure);
         }
@@ -482,16 +456,12 @@ private:
 
     void addStructureTransitionCheck(NodeOrigin origin, unsigned indexInBlock, JSCell* cell)
     {
+        if (m_graph.watchpoints().consider(cell->structure()))
+            return;
+
         Node* weakConstant = m_insertionSet.insertNode(
             indexInBlock, speculationFromValue(cell), WeakJSConstant, origin, OpInfo(cell));
         
-        if (m_graph.watchpoints().isStillValid(cell->structure()->transitionWatchpointSet())) {
-            m_insertionSet.insertNode(
-                indexInBlock, SpecNone, StructureTransitionWatchpoint, origin,
-                OpInfo(cell->structure()), Edge(weakConstant, CellUse));
-            return;
-        }
-
         m_insertionSet.insertNode(
             indexInBlock, SpecNone, CheckStructure, origin,
             OpInfo(m_graph.addStructureSet(cell->structure())), Edge(weakConstant, CellUse));
index a7704f4..3155da4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -62,14 +62,12 @@ void DesiredWatchpoints::addLazily(JSArrayBufferView* view)
     m_bufferViews.addLazily(view);
 }
 
-void DesiredWatchpoints::addLazily(CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSet* set)
+bool DesiredWatchpoints::consider(Structure* structure)
 {
-    m_sets.addLazily(codeOrigin, exitKind, set);
-}
-
-void DesiredWatchpoints::addLazily(CodeOrigin codeOrigin, ExitKind exitKind, InlineWatchpointSet& set)
-{
-    m_inlineSets.addLazily(codeOrigin, exitKind, &set);
+    if (!structure->dfgShouldWatch())
+        return false;
+    addLazily(structure->transitionWatchpointSet());
+    return true;
 }
 
 void DesiredWatchpoints::reallyAdd(CodeBlock* codeBlock, CommonData& commonData)
index 3e07f9b..b330f0a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 namespace JSC { namespace DFG {
 
-template<typename WatchpointSetType>
-struct WatchpointForGenericWatchpointSet {
-    WatchpointForGenericWatchpointSet()
-        : m_exitKind(ExitKindUnset)
-        , m_set(0)
-    {
-    }
-    
-    WatchpointForGenericWatchpointSet(
-        CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSetType* set)
-        : m_codeOrigin(codeOrigin)
-        , m_exitKind(exitKind)
-        , m_set(set)
-    {
-    }
-    
-    CodeOrigin m_codeOrigin;
-    ExitKind m_exitKind;
-    WatchpointSetType* m_set;
-};
+class Graph;
 
 template<typename T>
 struct GenericSetAdaptor {
@@ -95,12 +76,6 @@ public:
         m_sets.add(set);
     }
     
-    void addLazily(CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSetType* set)
-    {
-        m_profiledWatchpoints.append(
-            WatchpointForGenericWatchpointSet<WatchpointSetType>(codeOrigin, exitKind, set));
-    }
-    
     void reallyAdd(CodeBlock* codeBlock, CommonData& common)
     {
         RELEASE_ASSERT(!m_reallyAdded);
@@ -112,14 +87,6 @@ public:
             Adaptor::add(codeBlock, *iter, &common.watchpoints.last());
         }
         
-        for (unsigned i = m_profiledWatchpoints.size(); i--;) {
-            WatchpointForGenericWatchpointSet<WatchpointSetType> watchpoint =
-                m_profiledWatchpoints[i];
-            common.profiledWatchpoints.append(
-                ProfiledCodeBlockJettisoningWatchpoint(watchpoint.m_codeOrigin, watchpoint.m_exitKind, codeBlock));
-            Adaptor::add(codeBlock, watchpoint.m_set, &common.profiledWatchpoints.last());
-        }
-        
         m_reallyAdded = true;
     }
     
@@ -132,53 +99,16 @@ public:
                 return false;
         }
         
-        for (unsigned i = m_profiledWatchpoints.size(); i--;) {
-            if (Adaptor::hasBeenInvalidated(m_profiledWatchpoints[i].m_set))
-                return false;
-        }
-        
         return true;
     }
     
-#if ASSERT_DISABLED
-    bool isStillValid(WatchpointSetType* set)
+    bool isWatched(WatchpointSetType* set) const
     {
-        return !Adaptor::hasBeenInvalidated(set);
-    }
-    
-    bool shouldAssumeMixedState(WatchpointSetType*)
-    {
-        return true;
-    }
-#else
-    bool isStillValid(WatchpointSetType* set)
-    {
-        bool result = !Adaptor::hasBeenInvalidated(set);
-        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;
-        
-        return iter->value != !Adaptor::hasBeenInvalidated(set);
-    }
-#endif
-    
-    bool isValidOrMixed(WatchpointSetType* set)
-    {
-        return isStillValid(set) || shouldAssumeMixedState(set);
+        return m_sets.contains(set);
     }
 
 private:
-    Vector<WatchpointForGenericWatchpointSet<WatchpointSetType>> m_profiledWatchpoints;
     HashSet<WatchpointSetType*> m_sets;
-#if !ASSERT_DISABLED
-    StateMap m_firstKnownState;
-#endif
     bool m_reallyAdded;
 };
 
@@ -190,48 +120,24 @@ public:
     void addLazily(WatchpointSet*);
     void addLazily(InlineWatchpointSet&);
     void addLazily(JSArrayBufferView*);
-    void addLazily(CodeOrigin, ExitKind, WatchpointSet*);
-    void addLazily(CodeOrigin, ExitKind, InlineWatchpointSet&);
+    
+    bool consider(Structure*);
     
     void reallyAdd(CodeBlock*, CommonData&);
     
     bool areStillValid() const;
     
-    bool isStillValid(WatchpointSet* set)
-    {
-        return m_sets.isStillValid(set);
-    }
-    bool isStillValid(InlineWatchpointSet& set)
-    {
-        return m_inlineSets.isStillValid(&set);
-    }
-    bool isStillValid(JSArrayBufferView* view)
-    {
-        return m_bufferViews.isStillValid(view);
-    }
-    bool shouldAssumeMixedState(WatchpointSet* set)
-    {
-        return m_sets.shouldAssumeMixedState(set);
-    }
-    bool shouldAssumeMixedState(InlineWatchpointSet& set)
-    {
-        return m_inlineSets.shouldAssumeMixedState(&set);
-    }
-    bool shouldAssumeMixedState(JSArrayBufferView* view)
-    {
-        return m_bufferViews.shouldAssumeMixedState(view);
-    }
-    bool isValidOrMixed(WatchpointSet* set)
+    bool isWatched(WatchpointSet* set)
     {
-        return m_sets.isValidOrMixed(set);
+        return m_sets.isWatched(set);
     }
-    bool isValidOrMixed(InlineWatchpointSet& set)
+    bool isWatched(InlineWatchpointSet& set)
     {
-        return m_inlineSets.isValidOrMixed(&set);
+        return m_inlineSets.isWatched(&set);
     }
-    bool isValidOrMixed(JSArrayBufferView* view)
+    bool isWatched(JSArrayBufferView* view)
     {
-        return m_bufferViews.isValidOrMixed(view);
+        return m_bufferViews.isWatched(view);
     }
     
 private:
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
new file mode 100644 (file)
index 0000000..54c1769
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "DFGDoesGC.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGGraph.h"
+#include "DFGNode.h"
+#include "Operations.h"
+
+namespace JSC { namespace DFG {
+
+bool doesGC(Graph& graph, Node* node)
+{
+    if (graph.clobbersWorld(node))
+        return true;
+    
+    // Now consider nodes that don't clobber the world but that still may GC. This includes all
+    // nodes. By convention we put world-clobbering nodes in the block of "false" cases but we can
+    // put them anywhere.
+    switch (node->op()) {
+    case JSConstant:
+    case DoubleConstant:
+    case Int52Constant:
+    case WeakJSConstant:
+    case Identity:
+    case GetCallee:
+    case GetLocal:
+    case SetLocal:
+    case MovHint:
+    case ZombieHint:
+    case GetArgument:
+    case Phantom:
+    case HardPhantom:
+    case Upsilon:
+    case Phi:
+    case Flush:
+    case PhantomLocal:
+    case GetLocalUnlinked:
+    case SetArgument:
+    case BitAnd:
+    case BitOr:
+    case BitXor:
+    case BitLShift:
+    case BitRShift:
+    case BitURShift:
+    case ValueToInt32:
+    case UInt32ToNumber:
+    case DoubleAsInt32:
+    case ArithAdd:
+    case ArithSub:
+    case ArithNegate:
+    case ArithMul:
+    case ArithIMul:
+    case ArithDiv:
+    case ArithMod:
+    case ArithAbs:
+    case ArithMin:
+    case ArithMax:
+    case ArithSqrt:
+    case ArithFRound:
+    case ArithSin:
+    case ArithCos:
+    case ValueAdd:
+    case GetById:
+    case GetByIdFlush:
+    case PutById:
+    case PutByIdFlush:
+    case PutByIdDirect:
+    case CheckStructure:
+    case CheckExecutable:
+    case GetButterfly:
+    case CheckArray:
+    case GetScope:
+    case GetMyScope:
+    case SkipTopScope:
+    case SkipScope:
+    case GetClosureRegisters:
+    case GetClosureVar:
+    case PutClosureVar:
+    case GetGlobalVar:
+    case PutGlobalVar:
+    case VariableWatchpoint:
+    case VarInjectionWatchpoint:
+    case CheckFunction:
+    case AllocationProfileWatchpoint:
+    case RegExpExec:
+    case RegExpTest:
+    case CompareLess:
+    case CompareLessEq:
+    case CompareGreater:
+    case CompareGreaterEq:
+    case CompareEq:
+    case CompareEqConstant:
+    case CompareStrictEq:
+    case Call:
+    case Construct:
+    case Breakpoint:
+    case ProfileWillCall:
+    case ProfileDidCall:
+    case CheckHasInstance:
+    case InstanceOf:
+    case IsUndefined:
+    case IsBoolean:
+    case IsNumber:
+    case IsString:
+    case IsObject:
+    case IsFunction:
+    case TypeOf:
+    case LogicalNot:
+    case ToPrimitive:
+    case ToString:
+    case In:
+    case TearOffActivation:
+    case PhantomArguments:
+    case TearOffArguments:
+    case GetMyArgumentsLength:
+    case GetMyArgumentByVal:
+    case GetMyArgumentsLengthSafe:
+    case GetMyArgumentByValSafe:
+    case CheckArgumentsNotCreated:
+    case Jump:
+    case Branch:
+    case Switch:
+    case Return:
+    case Throw:
+    case CountExecution:
+    case ForceOSRExit:
+    case CheckWatchdogTimer:
+    case StringFromCharCode:
+    case Unreachable:
+    case ExtractOSREntryLocal:
+    case CheckTierUpInLoop:
+    case CheckTierUpAtReturn:
+    case CheckTierUpAndOSREnter:
+    case LoopHint:
+    case StoreBarrier:
+    case StoreBarrierWithNullCheck:
+    case InvalidationPoint:
+    case NotifyWrite:
+    case FunctionReentryWatchpoint:
+    case TypedArrayWatchpoint:
+    case CheckInBounds:
+    case ConstantStoragePointer:
+    case Check:
+    case MultiGetByOffset:
+    case ValueRep:
+    case DoubleRep:
+    case Int52Rep:
+    case GetGetter:
+    case GetSetter:
+    case GetByVal:
+    case GetIndexedPropertyStorage:
+    case GetArrayLength:
+    case ArrayPush:
+    case ArrayPop:
+    case StringCharAt:
+    case StringCharCodeAt:
+    case GetTypedArrayByteOffset:
+    case PutByValDirect:
+    case PutByVal:
+    case PutByValAlias:
+    case PutStructure:
+    case PhantomPutStructure:
+    case GetByOffset:
+    case GetGetterSetterByOffset:
+    case PutByOffset:
+    case FiatInt52:
+    case BooleanToNumber:
+        return false;
+
+    case CreateActivation:
+    case CreateArguments:
+    case ToThis:
+    case CreateThis:
+    case AllocatePropertyStorage:
+    case ReallocatePropertyStorage:
+    case Arrayify:
+    case ArrayifyToStructure:
+    case NewObject:
+    case NewArray:
+    case NewArrayWithSize:
+    case NewArrayBuffer:
+    case NewRegexp:
+    case NewStringObject:
+    case MakeRope:
+    case NewFunctionNoCheck:
+    case NewFunction:
+    case NewFunctionExpression:
+    case NewTypedArray:
+    case ThrowReferenceError:
+        return true;
+        
+    case MultiPutByOffset:
+        return node->multiPutByOffsetData().reallocatesStorage();
+
+    case LastNodeType:
+        RELEASE_ASSERT_NOT_REACHED();
+        return true;
+    }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+    return true;
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.h b/Source/JavaScriptCore/dfg/DFGDoesGC.h
new file mode 100644 (file)
index 0000000..4503d21
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGDoesGC_h
+#define DFGDoesGC_h
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+class Graph;
+struct Node;
+
+bool doesGC(Graph&, Node*);
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGDoesGC_h
+
index 1ad8113..4c49417 100644 (file)
@@ -927,7 +927,6 @@ private:
 
         case CheckExecutable:
         case CheckStructure:
-        case StructureTransitionWatchpoint:
         case CheckFunction:
         case CheckHasInstance:
         case CreateThis:
@@ -1357,7 +1356,7 @@ private:
         
         JSObject* stringPrototypeObject = asObject(stringObjectStructure->storedPrototype());
         Structure* stringPrototypeStructure = stringPrototypeObject->structure();
-        if (!m_graph.watchpoints().isStillValid(stringPrototypeStructure->transitionWatchpointSet()))
+        if (!m_graph.watchpoints().consider(stringPrototypeStructure))
             return false;
         
         if (stringPrototypeStructure->isDictionary())
index 0156c8b..412e35e 100644 (file)
@@ -77,6 +77,16 @@ Graph::Graph(VM& vm, Plan& plan, LongLivedState& longLivedState)
 
 Graph::~Graph()
 {
+    for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
+        BasicBlock* block = this->block(blockIndex);
+        if (!block)
+            continue;
+
+        for (unsigned phiIndex = block->phis.size(); phiIndex--;)
+            m_allocator.free(block->phis[phiIndex]);
+        for (unsigned nodeIndex = block->size(); nodeIndex--;)
+            m_allocator.free(block->at(nodeIndex));
+    }
     m_allocator.freeAll();
 }
 
@@ -211,8 +221,8 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext*
         out.print(comma, inContext(node->structureSet(), context));
     if (node->hasStructure())
         out.print(comma, inContext(*node->structure(), context));
-    if (node->hasStructureTransitionData())
-        out.print(comma, inContext(*node->structureTransitionData().previousStructure, context), " -> ", inContext(*node->structureTransitionData().newStructure, context));
+    if (node->hasTransition())
+        out.print(comma, pointerDumpInContext(node->transition(), context));
     if (node->hasFunction()) {
         out.print(comma, "function(", RawPointer(node->function()), ", ");
         if (node->function()->inherits(JSFunction::info())) {
@@ -338,9 +348,11 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext*
         out.print(comma, "R:", sortedListDump(reads.direct(), ","));
     if (!writes.isEmpty())
         out.print(comma, "W:", sortedListDump(writes.direct(), ","));
-    out.print(comma, "bc#", node->origin.semantic.bytecodeIndex);
-    if (node->origin.semantic != node->origin.forExit)
-        out.print(comma, "exit: ", node->origin.forExit);
+    if (node->origin.isSet()) {
+        out.print(comma, "bc#", node->origin.semantic.bytecodeIndex);
+        if (node->origin.semantic != node->origin.forExit)
+            out.print(comma, "exit: ", node->origin.forExit);
+    }
     
     out.print(")");
 
@@ -356,7 +368,7 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext*
 
 void Graph::dumpBlockHeader(PrintStream& out, const char* prefix, BasicBlock* block, PhiNodeDumpMode phiNodeDumpMode, DumpContext* context)
 {
-    out.print(prefix, "Block ", *block, " (", inContext(block->at(0)->origin.semantic, context), "): ", block->isReachable ? "" : "(skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n");
+    out.print(prefix, "Block ", *block, " (", inContext(block->at(0)->origin.semantic, context), "):", block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : "", block->cfaHasVisited ? "" : " (CFA-unreachable)", "\n");
     if (block->executionCount == block->executionCount)
         out.print(prefix, "  Execution count: ", block->executionCount, "\n");
     out.print(prefix, "  Predecessors:");
@@ -439,16 +451,17 @@ void Graph::dump(PrintStream& out, DumpContext* context)
         if (!block)
             continue;
         dumpBlockHeader(out, "", block, DumpAllPhis, context);
+        out.print("  States: ", block->cfaStructureClobberStateAtHead, "\n");
         switch (m_form) {
         case LoadStore:
         case ThreadedCPS: {
-            out.print("  vars before: ");
+            out.print("  Vars Before: ");
             if (block->cfaHasVisited)
                 out.print(inContext(block->valuesAtHead, context));
             else
                 out.print("<empty>");
             out.print("\n");
-            out.print("  var links: ", block->variablesAtHead, "\n");
+            out.print("  Var Links: ", block->variablesAtHead, "\n");
             break;
         }
             
@@ -464,16 +477,17 @@ void Graph::dump(PrintStream& out, DumpContext* context)
             dump(out, "", block->at(i), context);
             lastNode = block->at(i);
         }
+        out.print("  States: ", block->cfaBranchDirection, ", ", block->cfaStructureClobberStateAtTail, "\n");
         switch (m_form) {
         case LoadStore:
         case ThreadedCPS: {
-            out.print("  vars after: ");
+            out.print("  Vars After: ");
             if (block->cfaHasVisited)
                 out.print(inContext(block->valuesAtTail, context));
             else
                 out.print("<empty>");
             out.print("\n");
-            out.print("  var links: ", block->variablesAtTail, "\n");
+            out.print("  Var Links: ", block->variablesAtTail, "\n");
             break;
         }
             
@@ -800,8 +814,9 @@ JSArrayBufferView* Graph::tryGetFoldableView(Node* node)
     JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(valueOfJSConstant(node));
     if (!view)
         return 0;
-    if (!watchpoints().isStillValid(view))
+    if (!view->length())
         return 0;
+    WTF::loadLoadFence();
     return view;
 }
 
@@ -846,7 +861,6 @@ void Graph::visitChildren(SlotVisitor& visitor)
                     visitor.appendUnbarrieredReadOnlyPointer(node->structureSet()[i]);
                 break;
                 
-            case StructureTransitionWatchpoint:
             case NewObject:
             case ArrayifyToStructure:
             case NewStringObject:
@@ -858,9 +872,34 @@ void Graph::visitChildren(SlotVisitor& visitor)
             case AllocatePropertyStorage:
             case ReallocatePropertyStorage:
                 visitor.appendUnbarrieredReadOnlyPointer(
-                    node->structureTransitionData().previousStructure);
+                    node->transition()->previous);
                 visitor.appendUnbarrieredReadOnlyPointer(
-                    node->structureTransitionData().newStructure);
+                    node->transition()->next);
+                break;
+                
+            case MultiGetByOffset:
+                for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) {
+                    GetByIdVariant& variant = node->multiGetByOffsetData().variants[i];
+                    visitor.appendUnbarrieredReadOnlyValue(variant.specificValue());
+                    const StructureSet& set = variant.structureSet();
+                    for (unsigned j = set.size(); j--;)
+                        visitor.appendUnbarrieredReadOnlyPointer(set[j]);
+
+                    // Don't need to mark anything in the structure chain because that would
+                    // have been decomposed into CheckStructure's. Don't need to mark the
+                    // callLinkStatus because we wouldn't use MultiGetByOffset if any of the
+                    // variants did that.
+                    ASSERT(!variant.callLinkStatus());
+                }
+                break;
+                    
+            case MultiPutByOffset:
+                for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
+                    PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
+                    visitor.appendUnbarrieredReadOnlyPointer(variant.oldStructure());
+                    if (variant.kind() == PutByIdVariant::Transition)
+                        visitor.appendUnbarrieredReadOnlyPointer(variant.newStructure());
+                }
                 break;
                 
             default:
@@ -870,6 +909,35 @@ void Graph::visitChildren(SlotVisitor& visitor)
     }
 }
 
+void Graph::assertIsWatched(Structure* structure)
+{
+    if (!structure->dfgShouldWatch())
+        return;
+    if (watchpoints().isWatched(structure->transitionWatchpointSet()))
+        return;
+    
+    DFG_CRASH(*this, nullptr, toCString("Structure ", pointerDump(structure), " is watchable but isn't being watched.").data());
+}
+
+void Graph::handleAssertionFailure(
+    Node* node, const char* file, int line, const char* function, const char* assertion)
+{
+    startCrashing();
+    dataLog("DFG ASSERTION FAILED: ", assertion, "\n");
+    dataLog(file, "(", line, ") : ", function, "\n");
+    dataLog("\n");
+    if (node) {
+        dataLog("While handling node ", node, "\n");
+        dataLog("\n");
+    }
+    dataLog("Graph at time of failure:\n");
+    dump();
+    dataLog("\n");
+    dataLog("DFG ASSERTION FAILED: ", assertion, "\n");
+    dataLog(file, "(", line, ") : ", function, "\n");
+    CRASH();
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index c3a308b..3e596e4 100644 (file)
@@ -170,8 +170,12 @@ public:
         return constantRegister;
     }
     
+    void assertIsWatched(Structure* structure);
+    
     void convertToConstant(Node* node, JSValue value)
     {
+        if (value.isCell())
+            assertIsWatched(value.asCell()->structure());
         if (value.isObject())
             node->convertToWeakConstant(value.asCell());
         else
@@ -406,12 +410,6 @@ public:
         return &m_structureSet.last();
     }
     
-    StructureTransitionData* addStructureTransitionData(const StructureTransitionData& structureTransitionData)
-    {
-        m_structureTransitionData.append(structureTransitionData);
-        return &m_structureTransitionData.last();
-    }
-    
     JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin)
     {
         return m_codeBlock->globalObjectFor(codeOrigin);
@@ -462,8 +460,7 @@ public:
     
     bool masqueradesAsUndefinedWatchpointIsStillValid(const CodeOrigin& codeOrigin)
     {
-        return m_plan.watchpoints.isStillValid(
-            globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint());
+        return globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid();
     }
     
     bool hasGlobalExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
@@ -823,6 +820,10 @@ public:
     
     virtual void visitChildren(SlotVisitor&) override;
     
+    NO_RETURN_DUE_TO_CRASH void handleAssertionFailure(
+        Node* node, const char* file, int line, const char* function,
+        const char* assertion);
+    
     VM& m_vm;
     Plan& m_plan;
     CodeBlock* m_codeBlock;
@@ -839,7 +840,7 @@ public:
     SegmentedVector<VariableAccessData, 16> m_variableAccessData;
     SegmentedVector<ArgumentPosition, 8> m_argumentPositions;
     SegmentedVector<StructureSet, 16> m_structureSet;
-    SegmentedVector<StructureTransitionData, 8> m_structureTransitionData;
+    Bag<Transition> m_transitions;
     SegmentedVector<NewArrayBufferData, 4> m_newArrayBufferData;
     Bag<BranchData> m_branchData;
     Bag<SwitchData> m_switchData;
@@ -925,6 +926,17 @@ private:
         }                                                               \
     } while (false)
 
+#define DFG_ASSERT(graph, node, assertion) do {                         \
+        if (!!(assertion))                                              \
+            break;                                                      \
+        (graph).handleAssertionFailure(                                 \
+            (node), __FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \
+    } while (false)
+
+#define DFG_CRASH(graph, node, reason)                                  \
+    (graph).handleAssertionFailure(                                     \
+        (node), __FILE__, __LINE__, WTF_PRETTY_FUNCTION, (reason));
+
 } } // namespace JSC::DFG
 
 #endif
index 1121305..feda66d 100644 (file)
@@ -37,6 +37,8 @@
 
 namespace JSC { namespace DFG {
 
+static const bool verbose = false;
+
 InPlaceAbstractState::InPlaceAbstractState(Graph& graph)
     : m_graph(graph)
     , m_variables(m_graph.m_codeBlock->numParameters(), graph.m_localVars)
@@ -58,36 +60,20 @@ void InPlaceAbstractState::beginBasicBlock(BasicBlock* basicBlock)
         forNode(basicBlock->at(i)).clear();
 
     m_variables = basicBlock->valuesAtHead;
-    m_haveStructures = false;
-    for (size_t i = 0; i < m_variables.numberOfArguments(); ++i) {
-        if (m_variables.argument(i).hasClobberableState()) {
-            m_haveStructures = true;
-            break;
-        }
-    }
-    for (size_t i = 0; i < m_variables.numberOfLocals(); ++i) {
-        if (m_variables.local(i).hasClobberableState()) {
-            m_haveStructures = true;
-            break;
-        }
-    }
     
     if (m_graph.m_form == SSA) {
         HashMap<Node*, AbstractValue>::iterator iter = basicBlock->ssa->valuesAtHead.begin();
         HashMap<Node*, AbstractValue>::iterator end = basicBlock->ssa->valuesAtHead.end();
-        for (; iter != end; ++iter) {
+        for (; iter != end; ++iter)
             forNode(iter->key) = iter->value;
-            if (iter->value.hasClobberableState())
-                m_haveStructures = true;
-        }
     }
-    
     basicBlock->cfaShouldRevisit = false;
     basicBlock->cfaHasVisited = true;
     m_block = basicBlock;
     m_isValid = true;
     m_foundConstants = false;
     m_branchDirection = InvalidBranchDirection;
+    m_structureClobberState = basicBlock->cfaStructureClobberStateAtHead;
 }
 
 static void setLiveValues(HashMap<Node*, AbstractValue>& values, HashSet<Node*>& live)
@@ -106,6 +92,8 @@ void InPlaceAbstractState::initialize()
     root->cfaShouldRevisit = true;
     root->cfaHasVisited = false;
     root->cfaFoundConstants = false;
+    root->cfaStructureClobberStateAtHead = StructuresAreWatched;
+    root->cfaStructureClobberStateAtTail = StructuresAreWatched;
     for (size_t i = 0; i < root->valuesAtHead.numberOfArguments(); ++i) {
         root->valuesAtTail.argument(i).clear();
         if (m_graph.m_form == SSA) {
@@ -147,6 +135,8 @@ void InPlaceAbstractState::initialize()
         block->cfaShouldRevisit = false;
         block->cfaHasVisited = false;
         block->cfaFoundConstants = false;
+        block->cfaStructureClobberStateAtHead = StructuresAreWatched;
+        block->cfaStructureClobberStateAtTail = StructuresAreWatched;
         for (size_t i = 0; i < block->valuesAtHead.numberOfArguments(); ++i) {
             block->valuesAtHead.argument(i).clear();
             block->valuesAtTail.argument(i).clear();
@@ -204,6 +194,8 @@ bool InPlaceAbstractState::endBasicBlock(MergeMode mergeMode)
     bool changed = false;
     
     if (mergeMode != DontMerge || !ASSERT_DISABLED) {
+        changed |= checkAndSet(block->cfaStructureClobberStateAtTail, m_structureClobberState);
+    
         switch (m_graph.m_form) {
         case ThreadedCPS: {
             for (size_t argument = 0; argument < block->variablesAtTail.numberOfArguments(); ++argument) {
@@ -251,6 +243,7 @@ void InPlaceAbstractState::reset()
     m_block = 0;
     m_isValid = false;
     m_branchDirection = InvalidBranchDirection;
+    m_structureClobberState = StructuresAreWatched;
 }
 
 bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node)
@@ -311,11 +304,17 @@ bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
 
 bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to)
 {
+    if (verbose)
+        dataLog("   Merging from ", pointerDump(from), " to ", pointerDump(to), "\n");
     ASSERT(from->variablesAtTail.numberOfArguments() == to->variablesAtHead.numberOfArguments());
     ASSERT(from->variablesAtTail.numberOfLocals() == to->variablesAtHead.numberOfLocals());
     
     bool changed = false;
     
+    changed |= checkAndSet(
+        to->cfaStructureClobberStateAtHead,
+        DFG::merge(from->cfaStructureClobberStateAtTail, to->cfaStructureClobberStateAtHead));
+    
     switch (m_graph.m_form) {
     case ThreadedCPS: {
         for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument) {
@@ -338,8 +337,12 @@ bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to)
         HashSet<Node*>::iterator end = to->ssa->liveAtHead.end();
         for (; iter != end; ++iter) {
             Node* node = *iter;
+            if (verbose)
+                dataLog("      Merging for ", node, ": from ", from->ssa->valuesAtTail.find(node)->value, " to ", to->ssa->valuesAtHead.find(node)->value, "\n");
             changed |= to->ssa->valuesAtHead.find(node)->value.merge(
                 from->ssa->valuesAtTail.find(node)->value);
+            if (verbose)
+                dataLog("         Result: ", to->ssa->valuesAtHead.find(node)->value, "\n");
         }
         break;
     }
@@ -352,6 +355,8 @@ bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to)
     if (!to->cfaHasVisited)
         changed = true;
     
+    if (verbose)
+        dataLog("      Will revisit: ", changed, "\n");
     to->cfaShouldRevisit |= changed;
     
     return changed;
index 48da3aa..9a54623 100644 (file)
@@ -103,6 +103,9 @@ public:
     // Did the last executed node clobber the world?
     bool didClobber() const { return m_didClobber; }
     
+    // Are structures currently clobbered?
+    StructureClobberState structureClobberState() const { return m_structureClobberState; }
+    
     // Is the execution state still valid? This will be false if execute() has
     // returned false previously.
     bool isValid() const { return m_isValid; }
@@ -122,11 +125,10 @@ public:
     
     // Methods intended to be called from AbstractInterpreter.
     void setDidClobber(bool didClobber) { m_didClobber = didClobber; }
+    void setStructureClobberState(StructureClobberState value) { m_structureClobberState = value; }
     void setIsValid(bool isValid) { m_isValid = isValid; }
     void setBranchDirection(BranchDirection branchDirection) { m_branchDirection = branchDirection; }
     void setFoundConstants(bool foundConstants) { m_foundConstants = foundConstants; }
-    bool haveStructures() const { return m_haveStructures; } // It's always safe to return true.
-    void setHaveStructures(bool haveStructures) { m_haveStructures = haveStructures; }
 
 private:
     bool mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node*);
@@ -138,11 +140,11 @@ private:
     Operands<AbstractValue> m_variables;
     BasicBlock* m_block;
     
-    bool m_haveStructures;
     bool m_foundConstants;
     
     bool m_isValid;
     bool m_didClobber;
+    StructureClobberState m_structureClobberState;
     
     BranchDirection m_branchDirection; // This is only set for blocks that end in Branch and that execute to completion (i.e. m_isValid == true).
 };
index b3131a4..b2dc4d2 100644 (file)
@@ -68,13 +68,11 @@ public:
         } while (m_changed);
         
         if (!m_graph.block(0)->ssa->liveAtHead.isEmpty()) {
-            startCrashing();
-            dataLog(
-                "Bad liveness analysis result: live at root is not empty: ",
-                nodeListDump(m_graph.block(0)->ssa->liveAtHead), "\n");
-            dataLog("IR at time of error:\n");
-            m_graph.dump();
-            CRASH();
+            DFG_CRASH(
+                m_graph, nullptr,
+                toCString(
+                    "Bad liveness analysis result: live at root is not empty: ",
+                    nodeListDump(m_graph.block(0)->ssa->liveAtHead)).data());
         }
         
         return true;
index 9255394..a238a19 100644 (file)
@@ -38,6 +38,7 @@
 #include "DFGNodeFlags.h"
 #include "DFGNodeOrigin.h"
 #include "DFGNodeType.h"
+#include "DFGTransition.h"
 #include "DFGUseKind.h"
 #include "DFGVariableAccessData.h"
 #include "GetByIdVariant.h"
@@ -67,19 +68,6 @@ struct MultiPutByOffsetData {
     bool reallocatesStorage() const;
 };
 
-struct StructureTransitionData {
-    Structure* previousStructure;
-    Structure* newStructure;
-    
-    StructureTransitionData() { }
-    
-    StructureTransitionData(Structure* previousStructure, Structure* newStructure)
-        : previousStructure(previousStructure)
-        , newStructure(newStructure)
-    {
-    }
-};
-
 struct NewArrayBufferData {
     unsigned startConstant;
     unsigned numConstants;
@@ -485,20 +473,6 @@ struct Node {
         children.reset();
     }
     
-    void convertToStructureTransitionWatchpoint(Structure* structure)
-    {
-        ASSERT(m_op == CheckStructure || m_op == ArrayifyToStructure);
-        ASSERT(!child2());
-        ASSERT(!child3());
-        m_opInfo = bitwise_cast<uintptr_t>(structure);
-        m_op = StructureTransitionWatchpoint;
-    }
-    
-    void convertToStructureTransitionWatchpoint()
-    {
-        convertToStructureTransitionWatchpoint(structureSet().singletonStructure());
-    }
-    
     void convertToGetByOffset(unsigned storageAccessDataIndex, Edge storage)
     {
         ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == MultiGetByOffset);
@@ -1101,7 +1075,7 @@ struct Node {
         return reinterpret_cast<void*>(m_opInfo);
     }
 
-    bool hasStructureTransitionData()
+    bool hasTransition()
     {
         switch (op()) {
         case PutStructure:
@@ -1114,10 +1088,10 @@ struct Node {
         }
     }
     
-    StructureTransitionData& structureTransitionData()
+    Transition* transition()
     {
-        ASSERT(hasStructureTransitionData());
-        return *reinterpret_cast<StructureTransitionData*>(m_opInfo);
+        ASSERT(hasTransition());
+        return reinterpret_cast<Transition*>(m_opInfo);
     }
     
     bool hasStructureSet()
@@ -1139,7 +1113,6 @@ struct Node {
     bool hasStructure()
     {
         switch (op()) {
-        case StructureTransitionWatchpoint:
         case ArrayifyToStructure:
         case NewObject:
         case NewStringObject:
index 2575198..8bf72f8 100644 (file)
@@ -158,18 +158,6 @@ namespace JSC { namespace DFG {
     macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \
     macro(CheckStructure, NodeMustGenerate) \
     macro(CheckExecutable, NodeMustGenerate) \
-    /* Transition watchpoints are a contract between the party setting the watchpoint */\
-    /* and the runtime system, where the party promises that the child object once had */\
-    /* the structure being watched, and the runtime system in turn promises that the */\
-    /* watchpoint will be turned into an OSR exit if any object with that structure */\
-    /* ever transitions to a different structure. Hence, the child object must have */\
-    /* previously had a CheckStructure executed on it or we're dealing with an object */\
-    /* constant (WeakJSConstant) and the object was known to have that structure at */\
-    /* compile-time. In the latter case this means that no structure checks have to be */\
-    /* performed for this object by JITted code. In the former case this means that*/\
-    /* the object's structure does not need to be rechecked due to side-effecting */\
-    /* (clobbering) operations. */\
-    macro(StructureTransitionWatchpoint, NodeMustGenerate) \
     macro(PutStructure, NodeMustGenerate) \
     macro(PhantomPutStructure, NodeMustGenerate | NodeDoesNotExit) \
     macro(AllocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \
index c78a307..a6129c3 100644 (file)
@@ -63,6 +63,7 @@
 #include "DFGUnificationPhase.h"
 #include "DFGValidate.h"
 #include "DFGVirtualRegisterAllocationPhase.h"
+#include "DFGWatchableStructureWatchingPhase.h"
 #include "DFGWatchpointCollectionPhase.h"
 #include "Debugger.h"
 #include "JSCInlines.h"
@@ -234,6 +235,7 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
     performBackwardsPropagation(dfg);
     performPredictionPropagation(dfg);
     performFixup(dfg);
+    performWatchableStructureWatching(dfg);
     performInvalidationPointInjection(dfg);
     performTypeCheckHoisting(dfg);
     
@@ -311,6 +313,11 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
         performSSAConversion(dfg);
         performSSALowering(dfg);
         performCSE(dfg);
+        
+        // At this point we're not allowed to do any further code motion because our reasoning
+        // about code motion assumes that it's OK to insert GC points in random places.
+        
+        performStoreBarrierElision(dfg);
         performLivenessAnalysis(dfg);
         performCFA(dfg);
         performLICM(dfg);
index 1fcb3ab..dd0e387 100644 (file)
@@ -610,7 +610,6 @@ private:
         case SetArgument:
         case CheckStructure:
         case CheckExecutable:
-        case StructureTransitionWatchpoint:
         case CheckFunction:
         case PutStructure:
         case TearOffActivation:
index 866cb22..9dc4352 100644 (file)
@@ -279,22 +279,26 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
         return node->arrayMode().modeForPut().alreadyChecked(
             graph, node, state.forNode(graph.varArgChild(node, 0)));
 
-    case StructureTransitionWatchpoint:
-        return state.forNode(node->child1()).m_futurePossibleStructure.isSubsetOf(
-            StructureSet(node->structure()));
-        
     case PutStructure:
     case PhantomPutStructure:
     case AllocatePropertyStorage:
     case ReallocatePropertyStorage:
-        return state.forNode(node->child1()).m_currentKnownStructure.isSubsetOf(
-            StructureSet(node->structureTransitionData().previousStructure));
+        return state.forNode(node->child1()).m_structure.isSubsetOf(
+            StructureSet(node->transition()->previous));
         
     case GetByOffset:
     case GetGetterSetterByOffset:
-    case PutByOffset:
-        return state.forNode(node->child1()).m_currentKnownStructure.isValidOffset(
-            graph.m_storageAccessData[node->storageAccessDataIndex()].offset);
+    case PutByOffset: {
+        StructureAbstractValue& value = state.forNode(node->child1()).m_structure;
+        if (value.isTop())
+            return false;
+        PropertyOffset offset = graph.m_storageAccessData[node->storageAccessDataIndex()].offset;
+        for (unsigned i = value.size(); i--;) {
+            if (!value[i]->isValidOffset(offset))
+                return false;
+        }
+        return true;
+    }
         
     case LastNodeType:
         RELEASE_ASSERT_NOT_REACHED();
index 83b07e8..bed0da1 100644 (file)
@@ -4220,7 +4220,7 @@ bool SpeculativeJIT::compileRegExpExec(Node* node)
 
 void SpeculativeJIT::compileAllocatePropertyStorage(Node* node)
 {
-    if (node->structureTransitionData().previousStructure->couldHaveIndexingHeader()) {
+    if (node->transition()->previous->couldHaveIndexingHeader()) {
         SpeculateCellOperand base(this, node->child1());
         
         GPRReg baseGPR = base.gpr();
@@ -4240,8 +4240,8 @@ void SpeculativeJIT::compileAllocatePropertyStorage(Node* node)
     GPRReg baseGPR = base.gpr();
     GPRReg scratchGPR1 = scratch1.gpr();
         
-    ASSERT(!node->structureTransitionData().previousStructure->outOfLineCapacity());
-    ASSERT(initialOutOfLineCapacity == node->structureTransitionData().newStructure->outOfLineCapacity());
+    ASSERT(!node->transition()->previous->outOfLineCapacity());
+    ASSERT(initialOutOfLineCapacity == node->transition()->next->outOfLineCapacity());
     
     JITCompiler::Jump slowPath =
         emitAllocateBasicStorage(
@@ -4259,11 +4259,11 @@ void SpeculativeJIT::compileAllocatePropertyStorage(Node* node)
 
 void SpeculativeJIT::compileReallocatePropertyStorage(Node* node)
 {
-    size_t oldSize = node->structureTransitionData().previousStructure->outOfLineCapacity() * sizeof(JSValue);
+    size_t oldSize = node->transition()->previous->outOfLineCapacity() * sizeof(JSValue);
     size_t newSize = oldSize * outOfLineGrowthFactor;
-    ASSERT(newSize == node->structureTransitionData().newStructure->outOfLineCapacity() * sizeof(JSValue));
+    ASSERT(newSize == node->transition()->next->outOfLineCapacity() * sizeof(JSValue));
 
-    if (node->structureTransitionData().previousStructure->couldHaveIndexingHeader()) {
+    if (node->transition()->previous->couldHaveIndexingHeader()) {
         SpeculateCellOperand base(this, node->child1());
         
         GPRReg baseGPR = base.gpr();
index da17fb3..337e466 100644 (file)
@@ -3130,7 +3130,7 @@ void SpeculativeJIT::speculateStringObjectForStructure(Edge edge, StructureLocat
     Structure* stringObjectStructure =
         m_jit.globalObjectFor(m_currentNode->origin.semantic)->stringObjectStructure();
     
-    if (!m_state.forNode(edge).m_currentKnownStructure.isSubsetOf(StructureSet(stringObjectStructure))) {
+    if (!m_state.forNode(edge).m_structure.isSubsetOf(StructureSet(stringObjectStructure))) {
         speculationCheck(
             NotStringObject, JSValueRegs(), 0,
             m_jit.branchStructurePtr(
index a2965e0..fd4a2d3 100644 (file)
@@ -3739,29 +3739,6 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
         
-    case StructureTransitionWatchpoint: {
-        // There is a fascinating question here of what to do about array profiling.
-        // We *could* try to tell the OSR exit about where the base of the access is.
-        // The DFG will have kept it alive, though it may not be in a register, and
-        // we shouldn't really load it since that could be a waste. For now though,
-        // we'll just rely on the fact that when a watchpoint fires then that's
-        // quite a hint already.
-        
-        m_jit.addWeakReference(node->structure());
-        
-#if !ASSERT_DISABLED
-        SpeculateCellOperand op1(this, node->child1());
-        JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureIDOffset()), TrustedImmPtr(node->structure()));
-        m_jit.abortWithReason(DFGIneffectiveWatchpoint);
-        isOK.link(&m_jit);
-#else
-        speculateCell(node->child1());
-#endif
-
-        noResult(node);
-        break;
-    }
-        
     case PhantomPutStructure: {
         ASSERT(isKnownCell(node->child1().node()));
         m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node);
index c0055e4..4d08a1f 100644 (file)
@@ -3852,32 +3852,6 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
         
-    case StructureTransitionWatchpoint: {
-        // There is a fascinating question here of what to do about array profiling.
-        // We *could* try to tell the OSR exit about where the base of the access is.
-        // The DFG will have kept it alive, though it may not be in a register, and
-        // we shouldn't really load it since that could be a waste. For now though,
-        // we'll just rely on the fact that when a watchpoint fires then that's
-        // quite a hint already.
-
-        m_jit.addWeakReference(node->structure());
-
-#if !ASSERT_DISABLED
-        SpeculateCellOperand op1(this, node->child1());
-        JITCompiler::Jump isOK = m_jit.branchStructurePtr(
-            JITCompiler::Equal, 
-            JITCompiler::Address(op1.gpr(), JSCell::structureIDOffset()), 
-            node->structure());
-        m_jit.abortWithReason(DFGIneffectiveWatchpoint);
-        isOK.link(&m_jit);
-#else
-        speculateCell(node->child1());
-#endif
-        
-        noResult(node);
-        break;
-    }
-        
     case PhantomPutStructure: {
         ASSERT(isKnownCell(node->child1().node()));
         m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node);
@@ -3886,8 +3860,8 @@ void SpeculativeJIT::compile(Node* node)
     }
         
     case PutStructure: {
-        Structure* oldStructure = node->structureTransitionData().previousStructure;
-        Structure* newStructure = node->structureTransitionData().newStructure;
+        Structure* oldStructure = node->transition()->previous;
+        Structure* newStructure = node->transition()->next;
 
         m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node);
 
index 4217552..7f4c16e 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "DFGBasicBlock.h"
 #include "DFGClobberize.h"
+#include "DFGDoesGC.h"
 #include "DFGGraph.h"
 #include "DFGPhase.h"
 #include "JSCInlines.h"
@@ -58,11 +59,6 @@ public:
     }
 
 private:
-    bool couldCauseGC(Node* node)
-    {
-        return writesOverlap(m_graph, node, GCState);
-    }
-
     bool allocatesFreshObject(Node* node)
     {
         switch (node->op()) {
@@ -104,7 +100,7 @@ private:
 
     void handleNode(HashSet<Node*>& dontNeedBarriers, Node* node)
     {
-        if (couldCauseGC(node))
+        if (doesGC(m_graph, node))
             dontNeedBarriers.clear();
 
         if (allocatesFreshObject(node))
diff --git a/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.cpp b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.cpp
new file mode 100644 (file)
index 0000000..c3b7a2e
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "DFGStructureAbstractValue.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGGraph.h"
+
+namespace JSC { namespace DFG {
+
+// Comment out the empty SAMPLE() definition, and uncomment the one that uses SamplingRegion, if
+// you want extremely fine-grained profiling in this code.
+#define SAMPLE(name) 
+//#define SAMPLE(name) SamplingRegion samplingRegion(name)
+
+#if !ASSERT_DISABLED
+void StructureAbstractValue::assertIsWatched(Graph& graph) const
+{
+    SAMPLE("StructureAbstractValue assertIsWatched");
+
+    if (isTop())
+        return;
+    
+    for (unsigned i = size(); i--;)
+        graph.assertIsWatched(at(i));
+}
+#endif // !ASSERT_DISABLED
+
+void StructureAbstractValue::clobber()
+{
+    SAMPLE("StructureAbstractValue clobber");
+
+    // The premise of this approach to clobbering is that anytime we introduce
+    // a watchable structure into an abstract value, we watchpoint it. You can assert
+    // that this holds by calling assertIsWatched().
+        
+    if (isTop())
+        return;
+
+    setClobbered(true);
+        
+    if (m_set.isThin()) {
+        if (!m_set.singleStructure())
+            return;
+        if (!m_set.singleStructure()->dfgShouldWatch())
+            makeTopWhenThin();
+        return;
+    }
+        
+    StructureSet::OutOfLineList* list = m_set.structureList();
+    for (unsigned i = list->m_length; i--;) {
+        if (!list->list()[i]->dfgShouldWatch()) {
+            makeTop();
+            return;
+        }
+    }
+}
+
+void StructureAbstractValue::observeTransition(Structure* from, Structure* to)
+{
+    SAMPLE("StructureAbstractValue observeTransition");
+
+    if (isTop())
+        return;
+    
+    if (!m_set.contains(from))
+        return;
+    
+    if (from->dfgShouldWatch()) {
+        setClobbered(true);
+        return;
+    }
+    
+    if (!m_set.add(to))
+        return;
+    
+    if (m_set.size() > polymorphismLimit)
+        makeTop();
+}
+
+void StructureAbstractValue::observeTransitions(const TransitionVector& vector)
+{
+    SAMPLE("StructureAbstractValue observeTransitions");
+
+    if (isTop())
+        return;
+    
+    StructureSet newStructures;
+    for (unsigned i = vector.size(); i--;) {
+        if (!m_set.contains(vector[i].previous))
+            continue;
+        
+        if (vector[i].previous->dfgShouldWatch())
+            setClobbered(true);
+        else
+            newStructures.add(vector[i].next);
+    }
+    
+    if (!m_set.merge(newStructures))
+        return;
+    
+    if (m_set.size() > polymorphismLimit)
+        makeTop();
+}
+
+bool StructureAbstractValue::add(Structure* structure)
+{
+    SAMPLE("StructureAbstractValue add");
+
+    if (isTop())
+        return false;
+    
+    if (!m_set.add(structure))
+        return false;
+    
+    if (m_set.size() > polymorphismLimit)
+        makeTop();
+    
+    return true;
+}
+
+bool StructureAbstractValue::merge(const StructureSet& other)
+{
+    SAMPLE("StructureAbstractValue merge set");
+
+    if (isTop())
+        return false;
+    
+    return mergeNotTop(other);
+}
+
+bool StructureAbstractValue::mergeSlow(const StructureAbstractValue& other)
+{
+    SAMPLE("StructureAbstractValue merge value slow");
+
+    // It isn't immediately obvious that the code below is doing the right thing, so let's go
+    // through it.
+    //
+    // This not clobbered, other not clobbered: Clearly, we don't want to make anything clobbered
+    // since we just have two sets and we are merging them. mergeNotTop() can handle this just
+    // fine.
+    //
+    // This clobbered, other clobbered: Clobbered means that we have a set of things, plus we
+    // temporarily have the set of all things but the latter will go away once we hit the next
+    // invalidation point. This allows us to merge two clobbered sets the natural way. For now
+    // the set will still be TOP (and so we keep the clobbered bit set), but we know that after
+    // invalidation, we will have the union of the this and other.
+    //
+    // This clobbered, other not clobbered: It's safe to merge in other for both before and after
+    // invalidation, so long as we leave the clobbered bit set. Before invalidation this has no
+    // effect since the set will still appear to have all things in it. The way to think about
+    // what invalidation would do is imagine if we had a set A that was clobbered and a set B
+    // that wasn't and we considered the following two cases. Note that we expect A to be the
+    // same at the end in both cases:
+    //
+    //            A.merge(B)                             InvalidationPoint
+    //            InvalidationPoint                      A.merge(B)
+    //
+    // The fact that we expect A to be the same in both cases means that we want to merge other
+    // into this but keep the clobbered bit.
+    //
+    // This not clobbered, other clobbered: This is just the converse of the previous case. We
+    // want to merge other into this and set the clobbered bit.
+    
+    bool changed = false;
+    
+    if (!isClobbered() && other.isClobbered()) {
+        setClobbered(true);
+        changed = true;
+    }
+    
+    changed |= mergeNotTop(other.m_set);
+    
+    return changed;
+}
+
+bool StructureAbstractValue::mergeNotTop(const StructureSet& other)
+{
+    SAMPLE("StructureAbstractValue merge not top");
+
+    if (!m_set.merge(other))
+        return false;
+    
+    if (m_set.size() > polymorphismLimit)
+        makeTop();
+    
+    return true;
+}
+
+void StructureAbstractValue::filter(const StructureSet& other)
+{
+    SAMPLE("StructureAbstractValue filter set");
+
+    if (isTop()) {
+        m_set = other;
+        return;
+    }
+    
+    if (isClobbered()) {
+        // We have two choices here:
+        //
+        // Do nothing: It's legal to keep our set intact, which would essentially mean that for
+        // now, our set would behave like TOP but after the next invalidation point it wold be
+        // a finite set again. This may be a good choice if 'other' is much bigger than our
+        // m_set.
+        //
+        // Replace m_set with other and clear the clobber bit: This is also legal, and means that
+        // we're no longer clobbered. This is usually better because it immediately gives us a
+        // smaller set.
+        //
+        // This scenario should come up rarely. We usually don't do anything to an abstract value
+        // after it is clobbered. But we apply some heuristics.
+        
+        if (other.size() > m_set.size() + clobberedSupremacyThreshold)
+            return; // Keep the clobbered set.
+        
+        m_set = other;
+        setClobbered(false);
+        return;
+    }
+    
+    m_set.filter(other);
+}
+
+void StructureAbstractValue::filter(const StructureAbstractValue& other)
+{
+    SAMPLE("StructureAbstractValue filter value");
+
+    if (other.isTop())
+        return;
+    
+    if (other.isClobbered()) {
+        if (isTop())
+            return;
+        
+        if (!isClobbered()) {
+            // See justification in filter(const StructureSet&), above. An unclobbered set is
+            // almost always better.
+            if (m_set.size() > other.m_set.size() + clobberedSupremacyThreshold)
+                *this = other; // Keep the clobbered set.
+            return;
+        }
+
+        m_set.filter(other.m_set);
+        return;
+    }
+    
+    filter(other.m_set);
+}
+
+namespace {
+
+class ConformsToType {
+public:
+    ConformsToType(SpeculatedType type)
+        : m_type(type)
+    {
+    }
+    
+    bool operator()(Structure* structure)
+    {
+        return !!(speculationFromStructure(structure) & m_type);
+    }
+private:
+    SpeculatedType m_type;
+};
+
+} // anonymous namespace
+
+void StructureAbstractValue::filterSlow(SpeculatedType type)
+{
+    SAMPLE("StructureAbstractValue filter type slow");
+
+    if (!(type & SpecCell)) {
+        clear();
+        return;
+    }
+    
+    ASSERT(!isTop());
+    
+    ConformsToType conformsToType(type);
+    m_set.genericFilter(conformsToType);
+}
+
+bool StructureAbstractValue::contains(Structure* structure) const
+{
+    SAMPLE("StructureAbstractValue contains");
+
+    if (isTop() || isClobbered())
+        return true;
+    
+    return m_set.contains(structure);
+}
+
+bool StructureAbstractValue::isSubsetOf(const StructureSet& other) const
+{
+    SAMPLE("StructureAbstractValue isSubsetOf set");
+
+    if (isTop() || isClobbered())
+        return false;
+    
+    return m_set.isSubsetOf(other);
+}
+
+bool StructureAbstractValue::isSubsetOf(const StructureAbstractValue& other) const
+{
+    SAMPLE("StructureAbstractValue isSubsetOf value");
+
+    if (isTop())
+        return false;
+    
+    if (other.isTop())
+        return true;
+    
+    if (isClobbered() == other.isClobbered())
+        return m_set.isSubsetOf(other.m_set);
+    
+    // Here it gets tricky. If in doubt, return false!
+    
+    if (isClobbered())
+        return false; // A clobbered set is never a subset of an unclobbered set.
+    
+    // An unclobbered set is currently a subset of a clobbered set, but it may not be so after
+    // invalidation.
+    return m_set.isSubsetOf(other.m_set);
+}
+
+bool StructureAbstractValue::isSupersetOf(const StructureSet& other) const
+{
+    SAMPLE("StructureAbstractValue isSupersetOf set");
+
+    if (isTop() || isClobbered())
+        return true;
+    
+    return m_set.isSupersetOf(other);
+}
+
+bool StructureAbstractValue::overlaps(const StructureSet& other) const
+{
+    SAMPLE("StructureAbstractValue overlaps set");
+
+    if (isTop() || isClobbered())
+        return true;
+    
+    return m_set.overlaps(other);
+}
+
+bool StructureAbstractValue::overlaps(const StructureAbstractValue& other) const
+{
+    SAMPLE("StructureAbstractValue overlaps value");
+
+    if (other.isTop() || other.isClobbered())
+        return true;
+    
+    return overlaps(other.m_set);
+}
+
+bool StructureAbstractValue::equalsSlow(const StructureAbstractValue& other) const
+{
+    SAMPLE("StructureAbstractValue equalsSlow");
+
+    ASSERT(m_set.m_pointer != other.m_set.m_pointer);
+    ASSERT(!isTop());
+    ASSERT(!other.isTop());
+    
+    return m_set == other.m_set
+        && isClobbered() == other.isClobbered();
+}
+
+void StructureAbstractValue::dumpInContext(PrintStream& out, DumpContext* context) const
+{
+    if (isClobbered())
+        out.print("Clobbered:");
+    
+    if (isTop())
+        out.print("TOP");
+    else
+        out.print(inContext(m_set, context));
+}
+
+void StructureAbstractValue::dump(PrintStream& out) const
+{
+    dumpInContext(out, 0);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
index 10e476c..f9b4b18 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,6 +28,7 @@
 
 #if ENABLE(DFG_JIT)
 
+#include "DFGTransition.h"
 #include "JSCell.h"
 #include "SpeculatedType.h"
 #include "DumpContext.h"
@@ -37,300 +38,190 @@ namespace JSC { namespace DFG {
 
 class StructureAbstractValue {
 public:
-    StructureAbstractValue()
-        : m_structure(0)
+    StructureAbstractValue() { }
+    StructureAbstractValue(Structure* structure)
+        : m_set(structure)
     {
+        setClobbered(false);
     }
-    
-    StructureAbstractValue(Structure* structure)
-        : m_structure(structure)
+    StructureAbstractValue(const StructureSet& other)
+        : m_set(other)
+    {
+        setClobbered(false);
+    }
+    ALWAYS_INLINE StructureAbstractValue(const StructureAbstractValue& other)
+        : m_set(other.m_set)
     {
+        setClobbered(other.isClobbered());
     }
     
-    StructureAbstractValue(const StructureSet& set)
+    ALWAYS_INLINE StructureAbstractValue& operator=(const StructureAbstractValue& other)
     {
-        switch (set.size()) {
-        case 0:
-            m_structure = 0;
-            break;
-            
-        case 1:
-            m_structure = set[0];
-            break;
-            
-        default:
-            m_structure = topValue();
-            break;
-        }
+        m_set = other.m_set;
+        setClobbered(other.isClobbered());
+        return *this;
     }
     
     void clear()
     {
-        m_structure = 0;
+        m_set.clear();
+        setClobbered(false);
     }
     
     void makeTop()
     {
-        m_structure = topValue();
+        m_set.deleteStructureListIfNecessary();
+        m_set.m_pointer = topValue;
     }
     
-    static StructureAbstractValue top()
-    {
-        StructureAbstractValue value;
-        value.makeTop();
-        return value;
-    }
+#if ASSERT_DISABLED
+    void assertIsWatched(Graph&) const { }
+#else
+    void assertIsWatched(Graph&) const;
+#endif
     
-    void add(Structure* structure)
-    {
-        ASSERT(!contains(structure) && !isTop());
-        if (m_structure)
-            makeTop();
-        else
-            m_structure = structure;
-    }
+    void clobber();
+    void observeInvalidationPoint() { setClobbered(false); }
     
-    bool addAll(const StructureSet& other)
-    {
-        if (isTop() || !other.size())
-            return false;
-        if (other.size() > 1) {
-            makeTop();
-            return true;
-        }
-        if (!m_structure) {
-            m_structure = other[0];
-            return true;
-        }
-        if (m_structure == other[0])
-            return false;
-        makeTop();
-        return true;
-    }
+    void observeTransition(Structure* from, Structure* to);
+    void observeTransitions(const TransitionVector&);
     
-    bool addAll(const StructureAbstractValue& other)
+    static StructureAbstractValue top()
     {
-        if (!other.m_structure)
-            return false;
-        if (isTop())
-            return false;
-        if (other.isTop()) {
-            makeTop();
-            return true;
-        }
-        if (m_structure) {
-            if (m_structure == other.m_structure)
-                return false;
-            makeTop();
-            return true;
-        }
-        m_structure = other.m_structure;
-        return true;
+        StructureAbstractValue result;
+        result.m_set.m_pointer = topValue;
+        return result;
     }
     
-    bool contains(Structure* structure) const
-    {
-        if (isTop())
-            return true;
-        if (m_structure == structure)
-            return true;
-        return false;
-    }
+    bool isClear() const { return m_set.isEmpty(); }
+    bool isTop() const { return m_set.m_pointer == topValue; }
+    bool isNeitherClearNorTop() const { return !isClear() && !isTop(); }
     
-    bool isSubsetOf(const StructureSet& other) const
-    {
-        if (isTop())
-            return false;
-        if (!m_structure)
-            return true;
-        return other.contains(m_structure);
-    }
+    // A clobbered abstract value means that the set currently contains the m_set set of
+    // structures plus TOP, except that the "plus TOP" will go away at the next invalidation
+    // point. Note that it's tempting to think of this as "the set of structures in m_set plus
+    // the set of structures transition-reachable from m_set" - but this isn't really correct,
+    // since if we add an unwatchable structure after clobbering, the two definitions are not
+    // equivalent. If we do this, the new unwatchable structure will be added to m_set.
+    // Invalidation points do not try to "clip" the set of transition-reachable structures from
+    // m_set by looking at reachability as this would mean that the new set is TOP. Instead they
+    // literally assume that the set is just m_set rather than m_set plus TOP.
+    bool isClobbered() const { return m_set.getReservedFlag(); }
     
-    bool doesNotContainAnyOtherThan(Structure* structure) const
-    {
-        if (isTop())
-            return false;
-        if (!m_structure)
-            return true;
-        return m_structure == structure;
-    }
+    bool add(Structure* structure);
     
-    bool isSupersetOf(const StructureSet& other) const
-    {
-        if (isTop())
-            return true;
-        if (!other.size())
-            return true;
-        if (other.size() > 1)
-            return false;
-        return m_structure == other[0];
-    }
+    bool merge(const StructureSet& other);
     
-    bool isSubsetOf(const StructureAbstractValue& other) const
+    ALWAYS_INLINE bool merge(const StructureAbstractValue& other)
     {
-        if (other.isTop())
-            return true;
-        if (isTop())
+        if (other.isClear())
             return false;
-        if (m_structure) {
-            if (other.m_structure)
-                return m_structure == other.m_structure;
+        
+        if (isTop())
             return false;
-        }
-        return true;
-    }
-    
-    bool isSupersetOf(const StructureAbstractValue& other) const
-    {
-        return other.isSubsetOf(*this);
-    }
-    
-    void filter(const StructureSet& other)
-    {
-        if (!m_structure)
-            return;
         
-        if (isTop()) {
-            switch (other.size()) {
-            case 0:
-                m_structure = 0;
-                return;
-                
-            case 1:
-                m_structure = other[0];
-                return;
-                
-            default:
-                return;
-            }
+        if (other.isTop()) {
+            makeTop();
+            return true;
         }
         
-        if (other.contains(m_structure))
-            return;
-        
-        m_structure = 0;
+        return mergeSlow(other);
     }
     
-    void filter(const StructureAbstractValue& other)
-    {
-        if (isTop()) {
-            m_structure = other.m_structure;
-            return;
-        }
-        if (m_structure == other.m_structure)
-            return;
-        if (other.isTop())
-            return;
-        m_structure = 0;
-    }
+    void filter(const StructureSet& other);
+    void filter(const StructureAbstractValue& other);
     
-    void filter(SpeculatedType other)
+    ALWAYS_INLINE void filter(SpeculatedType type)
     {
-        if (!(other & SpecCell)) {
+        if (!(type & SpecCell)) {
             clear();
             return;
         }
-        
-        if (isClearOrTop())
-            return;
-
-        if (!(speculationFromStructure(m_structure) & other))
-            m_structure = 0;
+        if (isNeitherClearNorTop())
+            filterSlow(type);
     }
     
-    bool isClear() const
+    ALWAYS_INLINE bool operator==(const StructureAbstractValue& other) const
     {
-        return !m_structure;
+        if ((m_set.isThin() && other.m_set.isThin()) || isTop() || other.isTop())
+            return m_set.m_pointer == other.m_set.m_pointer;
+        
+        return equalsSlow(other);
     }
     
-    bool isTop() const { return m_structure == topValue(); }
-    
-    bool isClearOrTop() const { return m_structure <= topValue(); }
-    bool isNeitherClearNorTop() const { return !isClearOrTop(); }
-    
     size_t size() const
     {
         ASSERT(!isTop());
-        return !!m_structure;
+        return m_set.size();
     }
     
     Structure* at(size_t i) const
     {
         ASSERT(!isTop());
-        ASSERT(m_structure);
-        ASSERT_UNUSED(i, !i);
-        return m_structure;
+        return m_set.at(i);
     }
     
-    Structure* operator[](size_t i) const
-    {
-        return at(i);
-    }
+    Structure* operator[](size_t i) const { return at(i); }
     
-    Structure* last() const
+    // FIXME: Eliminate all uses of this method. There shouldn't be any
+    // special-casing for the one-structure case.
+    // https://bugs.webkit.org/show_bug.cgi?id=133229
+    Structure* onlyStructure() const
     {
+        if (isTop() || size() != 1)
+            return nullptr;
         return at(0);
     }
     
-    SpeculatedType speculationFromStructures() const
-    {
-        if (isTop())
-            return SpecCell;
-        if (isClear())
-            return SpecNone;
-        return speculationFromStructure(m_structure);
-    }
+    void dumpInContext(PrintStream&, DumpContext*) const;
+    void dump(PrintStream&) const;
     
-    bool isValidOffset(PropertyOffset offset)
-    {
-        if (isTop())
-            return false;
-        if (isClear())
-            return true;
-        return m_structure->isValidOffset(offset);
-    }
+    // The methods below are all conservative and err on the side of making 'this' appear bigger
+    // than it is. For example, contains() may return true if the set is clobbered or TOP.
+    // isSubsetOf() may return false in case of ambiguities. Therefore you should only perform
+    // optimizations as a consequence of the "this is smaller" return value - so false for
+    // contains(), true for isSubsetOf(), false for isSupersetOf(), and false for overlaps().
+
+    bool contains(Structure* structure) const;
     
-    bool hasSingleton() const
-    {
-        return isNeitherClearNorTop();
-    }
+    bool isSubsetOf(const StructureSet& other) const;
+    bool isSubsetOf(const StructureAbstractValue& other) const;
     
-    Structure* singleton() const
+    bool isSupersetOf(const StructureSet& other) const;
+    bool isSupersetOf(const StructureAbstractValue& other) const
     {
-        ASSERT(isNeitherClearNorTop());
-        return m_structure;
+        return other.isSubsetOf(*this);
     }
     
-    bool operator==(const StructureAbstractValue& other) const
-    {
-        return m_structure == other.m_structure;
-    }
+    bool overlaps(const StructureSet& other) const;
+    bool overlaps(const StructureAbstractV