Merge r169148, r169185, r169188, r169578, r169582, r169584, r169588, r169753 from ftlopt.
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: http://svn.webkit.org/repository/webkit/trunk@171380 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 8cfffd1..f778bd0 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -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
index 0000000..5c2a972
--- /dev/null
+++ b/LayoutTests/js/regress/ftl-library-inlining-dataview-expected.txt
@@ -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
index 0000000..628189d
--- /dev/null
+++ b/LayoutTests/js/regress/ftl-library-inlining-dataview.html
@@ -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
index 0000000..f04fdb3
--- /dev/null
+++ b/LayoutTests/js/regress/ftl-library-inlining-expected.txt
@@ -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
index 0000000..ffdaf2e
--- /dev/null
+++ b/LayoutTests/js/regress/ftl-library-inlining.html
@@ -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
index 0000000..09c5a7e
--- /dev/null
+++ b/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-expected.txt
@@ -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
index 0000000..11c52c4
--- /dev/null
+++ b/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple-expected.txt
@@ -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
index 0000000..859ad6b
--- /dev/null
+++ b/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple.html
@@ -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
index 0000000..d9b61b0
--- /dev/null
+++ b/LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination.html
@@ -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
index 0000000..1184ca9
--- /dev/null
+++ b/LayoutTests/js/regress/get-by-id-check-structure-elimination-expected.txt
@@ -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
index 0000000..8d56374
--- /dev/null
+++ b/LayoutTests/js/regress/get-by-id-check-structure-elimination.html
@@ -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
index 0000000..bf12441
--- /dev/null
+++ b/LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple-expected.txt
@@ -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
index 0000000..08f5d77
--- /dev/null
+++ b/LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple.html
@@ -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
index 0000000..e6bdd3f
--- /dev/null
+++ b/LayoutTests/js/regress/hoist-make-rope-expected.txt
@@ -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
index 0000000..6c3662d
--- /dev/null
+++ b/LayoutTests/js/regress/hoist-make-rope.html
@@ -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
index 0000000..12fbdf0
--- /dev/null
+++ b/LayoutTests/js/regress/script-tests/ftl-library-inlining-dataview.js
@@ -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
index 0000000..a107ae1
--- /dev/null
+++ b/LayoutTests/js/regress/script-tests/ftl-library-inlining.js
@@ -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
index 0000000..2f136d4
--- /dev/null
+++ b/LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination-simple.js
@@ -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
index 0000000..2c6bd87
--- /dev/null
+++ b/LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination.js
@@ -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
index 0000000..7e46546
--- /dev/null
+++ b/LayoutTests/js/regress/script-tests/get-by-id-check-structure-elimination.js
@@ -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
index 0000000..80ebfda
--- /dev/null
+++ b/LayoutTests/js/regress/script-tests/get-by-id-quadmorphic-check-structure-elimination-simple.js
@@ -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
index 0000000..4069615
--- /dev/null
+++ b/LayoutTests/js/regress/script-tests/hoist-make-rope.js
@@ -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;
+}
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 2a76770..4c27459 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -90,6 +90,7 @@
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 @@
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 @@
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 @@
dfg/DFGVariableEvent.cpp
dfg/DFGVariableEventStream.cpp
dfg/DFGVirtualRegisterAllocationPhase.cpp
+ dfg/DFGWatchableStructureWatchingPhase.cpp
dfg/DFGWatchpointCollectionPhase.cpp
dfg/DFGWorklist.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index a520355..437fdac 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -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.
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
index 89fdaec..eac7baa 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
@@ -343,6 +343,7 @@
<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" />
@@ -387,6 +388,7 @@
<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" />
@@ -441,11 +443,13 @@
<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" />
@@ -457,6 +461,7 @@
<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" />
@@ -989,6 +994,7 @@
<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" />
@@ -1064,11 +1070,13 @@
<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" />
@@ -1081,6 +1089,7 @@
<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" />
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index d1426df..356ec95 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -282,6 +282,7 @@
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, ); }; };
@@ -292,6 +293,8 @@
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, ); }; };
@@ -354,6 +357,7 @@
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 */; };
@@ -419,6 +423,7 @@
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, ); }; };
@@ -495,6 +500,8 @@
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 */; };
@@ -528,6 +535,8 @@
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 */; };
@@ -2094,6 +2103,7 @@
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>"; };
@@ -2104,6 +2114,8 @@
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>"; };
@@ -2164,6 +2176,7 @@
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>"; };
@@ -2229,6 +2242,7 @@
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>"; };
@@ -2316,6 +2330,8 @@
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>"; };
@@ -2351,6 +2367,8 @@
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>"; };
@@ -4689,6 +4707,8 @@
C2981FDB17BAFF4400A3BC98 /* DFGDesiredWriteBarriers.h */,
0FF427611591A1C9004CB9FF /* DFGDisassembler.cpp */,
0FF427621591A1C9004CB9FF /* DFGDisassembler.h */,
+ 0F5A1271192D9FDF008764A3 /* DFGDoesGC.cpp */,
+ 0F5A1272192D9FDF008764A3 /* DFGDoesGC.h */,
0FD81ACF154FB4EB00983E72 /* DFGDominators.cpp */,
0FD81AD0154FB4EB00983E72 /* DFGDominators.h */,
0F1E3A441534CBAD000F9456 /* DFGDoubleFormatState.h */,
@@ -4709,6 +4729,8 @@
0F9D339517FFC4E60073C2BC /* DFGFlushedAt.h */,
A7D89CE817A0B8CC00773AD8 /* DFGFlushFormat.cpp */,
A7D89CE917A0B8CC00773AD8 /* DFGFlushFormat.h */,
+ 2A88067619107D5500CB0BBB /* DFGFunctionWhitelist.cpp */,
+ 2A88067719107D5500CB0BBB /* DFGFunctionWhitelist.h */,
86EC9DB61328DF82002B2AD7 /* DFGGenerationInfo.h */,
86EC9DB71328DF82002B2AD7 /* DFGGraph.cpp */,
86EC9DB81328DF82002B2AD7 /* DFGGraph.h */,
@@ -4813,7 +4835,9 @@
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 */,
@@ -4824,6 +4848,8 @@
0FD8A32217D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.h */,
0FD8A32317D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp */,
0FD8A32417D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.h */,
+ 0FE7211B193B9C590031F6ED /* DFGTransition.cpp */,
+ 0FE7211C193B9C590031F6ED /* DFGTransition.h */,
0F63943C15C75F14006A597C /* DFGTypeCheckHoistingPhase.cpp */,
0F63943D15C75F14006A597C /* DFGTypeCheckHoistingPhase.h */,
0FBE0F6F16C1DB010082C5E8 /* DFGUnificationPhase.cpp */,
@@ -4845,12 +4871,12 @@
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>";
@@ -5036,6 +5062,7 @@
0F5541B01613C1FB00CE3E25 /* SpecialPointer.h */,
0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */,
0FD82E4F141DAEA100179C94 /* SpeculatedType.h */,
+ 0FB438A219270B1D00E1FBC9 /* StructureSet.cpp */,
0F93329B14CA7DC10085F3C6 /* StructureSet.h */,
0F766D3615AE4A1A008F363E /* StructureStubClearingWatchpoint.cpp */,
0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */,
@@ -5787,6 +5814,7 @@
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 */,
@@ -5828,6 +5856,7 @@
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 */,
@@ -5978,6 +6007,7 @@
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 */,
@@ -6196,6 +6226,7 @@
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 */,
@@ -6969,6 +7000,7 @@
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 */,
@@ -6998,6 +7030,7 @@
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 */,
@@ -7070,6 +7103,7 @@
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 */,
@@ -7187,6 +7221,7 @@
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 */,
@@ -7202,6 +7237,7 @@
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
index 0000000..eead0d6
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/StructureSet.cpp
@@ -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
+
diff --git a/Source/JavaScriptCore/bytecode/StructureSet.h b/Source/JavaScriptCore/bytecode/StructureSet.h
index d7087b9..0e9a467 100644
--- a/Source/JavaScriptCore/bytecode/StructureSet.h
+++ b/Source/JavaScriptCore/bytecode/StructureSet.h
@@ -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 StructureSet {
public:
- StructureSet() { }
+ StructureSet()
+ {
+ setEmpty();
+ }
StructureSet(Structure* structure)
{
- ASSERT(structure);
- m_structures.append(structure);
+ set(structure);
}
- void clear()
+ ALWAYS_INLINE StructureSet(const StructureSet& other)
{
- m_structures.clear();
+ copyFrom(other);
}
- void add(Structure* structure)
+ ALWAYS_INLINE StructureSet& operator=(const StructureSet& other)
{
- ASSERT(structure);
- ASSERT(!contains(structure));
- m_structures.append(structure);
+ if (this == &other)
+ return *this;
+ deleteStructureListIfNecessary();
+ copyFrom(other);
+ return *this;
}
- bool addAll(const StructureSet& other)
+ ~StructureSet()
{
- bool changed = false;
- for (size_t i = 0; i < other.size(); ++i) {
- if (contains(other[i]))
- continue;
- add(other[i]);
- changed = true;
+ deleteStructureListIfNecessary();
+ }
+
+ void clear();
+
+ Structure* onlyStructure() const
+ {
+ if (isThin()) {
+ ASSERT(singleStructure());
+ return singleStructure();
}
- return changed;
+ ASSERT(structureList()->m_length == 1);
+ return structureList()->list()[0];
}
- void remove(Structure* structure)
+ bool isEmpty() const
{
- 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();
+ bool result = isThin() && !singleStructure();
+ if (result)
+ ASSERT(m_pointer != reservedValue);
+ return result;
+ }
+
+ 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)
+ {
+ if (isThin()) {
+ if (!singleStructure())
+ return;
+ if (functor(singleStructure()))
+ return;
+ clear();
return;
}
- }
-
- bool contains(Structure* structure) const
- {
- for (size_t i = 0; i < m_structures.size(); ++i) {
- if (m_structures[i] == structure)
- return true;
+
+ 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 false;
+ if (!list->m_length)
+ clear();
}
- bool containsOnly(Structure* structure) const
- {
- if (size() != 1)
- return false;
- return singletonStructure() == structure;
- }
-
- bool isSubsetOf(const StructureSet& other) const
- {
- for (size_t i = 0; i < m_structures.size(); ++i) {
- if (!other.contains(m_structures[i]))
- return false;
- }
- return true;
- }
-
+ 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
{
- for (size_t i = 0; i < m_structures.size(); ++i) {
- if (other.contains(m_structures[i]))
- return true;
+ if (isThin())
+ return !!singleStructure();
+ return structureList()->m_length;
+ }
+
+ Structure* at(size_t i) const
+ {
+ 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(); }
-
- // Call this if you know that the structure set must consist of exactly
- // one structure.
- Structure* singletonStructure() const
- {
- ASSERT(m_structures.size() == 1);
- return m_structures[0];
- }
-
- Structure* at(size_t i) const { return m_structures.at(i); }
-
Structure* operator[](size_t i) const { return at(i); }
- Structure* last() const { return m_structures.last(); }
-
- SpeculatedType speculationFromStructures() const
+ Structure* last() const
{
- SpeculatedType result = SpecNone;
-
- for (size_t i = 0; i < m_structures.size(); ++i)
- mergeSpeculation(result, speculationFromStructure(m_structures[i]));
-
- return result;
- }
-
- ArrayModes arrayModesFromStructures() const
- {
- ArrayModes result = 0;
-
- for (size_t i = 0; i < m_structures.size(); ++i)
- mergeArrayModes(result, asArrayModes(m_structures[i]->indexingType()));
-
- return result;
- }
-
- bool operator==(const StructureSet& other) const
- {
- 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;
+ if (isThin()) {
+ ASSERT(singleStructure());
+ return singleStructure();
}
-
- return true;
+ return structureList()->list()[structureList()->m_length - 1];
}
- void dumpInContext(PrintStream& out, DumpContext* context) 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("]");
- }
+ bool operator==(const StructureSet& other) const;
- void dump(PrintStream& out) const
- {
- dumpInContext(out, 0);
- }
+ SpeculatedType speculationFromStructures() const;
+ ArrayModes arrayModesFromStructures() const;
+
+ void dumpInContext(PrintStream&, DumpContext*) const;
+ void dump(PrintStream&) const;
private:
friend class DFG::StructureAbstractValue;
- Vector<Structure*, 2> m_structures;
+ 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;
+
+ static const unsigned defaultStartingSize = 4;
+
+ bool addOutOfLine(Structure*);
+ bool containsOutOfLine(Structure*) const;
+
+ class ContainsOutOfLine {
+ public:
+ ContainsOutOfLine(const StructureSet& set)
+ : m_set(set)
+ {
+ }
+
+ 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);
+
+ class OutOfLineList {
+ public:
+ static OutOfLineList* create(unsigned capacity);
+ static void destroy(OutOfLineList*);
+
+ Structure** list() { return bitwise_cast<Structure**>(this + 1); }
+
+ OutOfLineList(unsigned length, unsigned capacity)
+ : m_length(length)
+ , m_capacity(capacity)
+ {
+ }
+
+ unsigned m_length;
+ unsigned m_capacity;
+ };
+
+ ALWAYS_INLINE void deleteStructureListIfNecessary()
+ {
+ if (!isThin() && m_pointer != reservedValue)
+ OutOfLineList::destroy(structureList());
+ }
+
+ bool isThin() const { return m_pointer & thinFlag; }
+
+ void* pointer() const
+ {
+ return bitwise_cast<void*>(m_pointer & ~flags);
+ }
+
+ Structure* singleStructure() const
+ {
+ ASSERT(isThin());
+ return static_cast<Structure*>(pointer());
+ }
+
+ OutOfLineList* structureList() const
+ {
+ ASSERT(!isThin());
+ return static_cast<OutOfLineList*>(pointer());
+ }
+
+ 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
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractHeap.h b/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
index 7c422e7..9507653 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
@@ -70,8 +70,7 @@
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) \
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h
index 97582ac..01f5a48 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h
@@ -114,6 +114,7 @@
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 @@
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 @@
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);
}
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 5e51dea..ba7403f 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -62,11 +62,17 @@
}
// 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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
break;
}
filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
- m_state.setHaveStructures(true);
break;
}
case Arrayify: {
@@ -1629,19 +1623,43 @@
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 @@
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 @@
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 @@
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 @@
if (variant.kind() == PutByIdVariant::Replace) {
filter(node->child1(), structure);
m_state.setFoundConstants(true);
- m_state.setHaveStructures(true);
done = true;
break;
}
@@ -1725,7 +1751,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
case InvalidationPoint:
node->setCanExit(true);
+ forAllValues(clobberLimit, AbstractValue::observeInvalidationPointFor);
+ m_state.setStructureClobberState(StructuresAreWatched);
break;
case CheckWatchdogTimer:
@@ -1955,6 +1986,7 @@
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 @@
}
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 @@
}
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>
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp b/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp
index d39ca87..b141206 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp
@@ -33,16 +33,29 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
return true;
if (!(m_type & ~SpecCell)
- && (!m_arrayModes
- || m_currentKnownStructure.isClear()))
+ && (!m_arrayModes || m_structure.isClear()))
return true;
return false;
@@ -275,12 +310,18 @@
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 @@
// 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 @@
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));
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
index 14363df..f71f073 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
@@ -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 @@
{
m_type = SpecNone;
m_arrayModes = 0;
- m_currentKnownStructure.clear();
- m_futurePossibleStructure.clear();
+ m_structure.clear();
m_value = JSValue();
checkConsistency();
}
@@ -75,15 +75,74 @@
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 @@
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 @@
}
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 @@
{
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 @@
} 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
{
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
diff --git a/Source/JavaScriptCore/dfg/DFGAllocator.h b/Source/JavaScriptCore/dfg/DFGAllocator.h
index 6e20fb3..09feb94 100644
--- a/Source/JavaScriptCore/dfg/DFGAllocator.h
+++ b/Source/JavaScriptCore/dfg/DFGAllocator.h
@@ -50,7 +50,7 @@
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*);
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
index 29572b9..a52404e 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
@@ -325,7 +325,6 @@
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 @@
}
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()))
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
index 7391c02..fa1e5e6 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
@@ -289,25 +289,48 @@
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 @@
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);
diff --git a/Source/JavaScriptCore/dfg/DFGAtTailAbstractState.h b/Source/JavaScriptCore/dfg/DFGAtTailAbstractState.h
index 7a872f9..9bf09da 100644
--- a/Source/JavaScriptCore/dfg/DFGAtTailAbstractState.h
+++ b/Source/JavaScriptCore/dfg/DFGAtTailAbstractState.h
@@ -54,12 +54,13 @@
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;
diff --git a/Source/JavaScriptCore/dfg/DFGBasicBlock.cpp b/Source/JavaScriptCore/dfg/DFGBasicBlock.cpp
index 5f3b480..fadf622 100644
--- a/Source/JavaScriptCore/dfg/DFGBasicBlock.cpp
+++ b/Source/JavaScriptCore/dfg/DFGBasicBlock.cpp
@@ -41,6 +41,8 @@
, cfaShouldRevisit(false)
, cfaFoundConstants(false)
, cfaDidFinish(true)
+ , cfaStructureClobberStateAtHead(StructuresAreWatched)
+ , cfaStructureClobberStateAtTail(StructuresAreWatched)
, cfaBranchDirection(InvalidBranchDirection)
#if !ASSERT_DISABLED
, isLinked(false)
diff --git a/Source/JavaScriptCore/dfg/DFGBasicBlock.h b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
index 19d5487..27f5877 100644
--- a/Source/JavaScriptCore/dfg/DFGBasicBlock.h
+++ b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
@@ -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 @@
bool cfaShouldRevisit;
bool cfaFoundConstants;
bool cfaDidFinish;
+ StructureClobberState cfaStructureClobberStateAtHead;
+ StructureClobberState cfaStructureClobberStateAtTail;
BranchDirection cfaBranchDirection;
#if !ASSERT_DISABLED
bool isLinked;
diff --git a/Source/JavaScriptCore/dfg/DFGBranchDirection.h b/Source/JavaScriptCore/dfg/DFGBranchDirection.h
index 811c898..cfde4eb 100644
--- a/Source/JavaScriptCore/dfg/DFGBranchDirection.h
+++ b/Source/JavaScriptCore/dfg/DFGBranchDirection.h
@@ -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 @@
{
switch (branchDirection) {
case InvalidBranchDirection:
- return "Invalid";
+ return "InvalidBranchDirection";
case TakeTrue:
return "TakeTrue";
case TakeFalse:
@@ -81,6 +81,15 @@
} } // 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
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 059c19a..ecffc42 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -1921,6 +1921,7 @@
Node* ByteCodeParser::emitPrototypeChecks(
Structure* structure, IntendedStructureChain* chain)
{
+ ASSERT(structure);
Node* base = 0;
m_graph.chains().addLazily(chain);
Structure* currentStructure = structure;
@@ -1962,7 +1963,7 @@
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 @@
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 @@
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 @@
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 @@
propertyStorage = addToGraph(GetButterfly, base);
}
- addToGraph(PutStructure, OpInfo(transitionData), base);
+ addToGraph(PutStructure, OpInfo(transition), base);
addToGraph(
PutByOffset,
@@ -3131,7 +3132,7 @@
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()));
diff --git a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
index 5f69de1..46b6021 100644
--- a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
@@ -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 @@
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 @@
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 @@
}
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()
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index 635ef21..5f0670e 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -460,17 +460,11 @@
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 @@
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 @@
}
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 @@
eliminate();
break;
- case StructureTransitionWatchpoint:
- if (cseMode == StoreElimination)
- break;
- if (structureTransitionWatchpointElimination(node->structure(), node->child1().node()))
- eliminate();
- break;
-
case PutStructure:
if (cseMode == NormalCSE)
break;
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index 17a59dd..ed967a5 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -35,15 +35,6 @@
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 @@
case Int52Rep:
case BooleanToNumber:
case FiatInt52:
+ case MakeRope:
return;
case MovHint:
@@ -158,6 +150,8 @@
case Breakpoint:
case ProfileWillCall:
case ProfileDidCall:
+ case StoreBarrier:
+ case StoreBarrierWithNullCheck:
write(SideState);
return;
@@ -174,7 +168,8 @@
case CreateActivation:
case CreateArguments:
- clobberizeForAllocation(read, write);
+ read(HeapObjectCount);
+ write(HeapObjectCount);
write(SideState);
write(Watchpoint_fire);
return;
@@ -186,7 +181,8 @@
case ToThis:
case CreateThis:
read(MiscFields);
- clobberizeForAllocation(read, write);
+ read(HeapObjectCount);
+ write(HeapObjectCount);
return;
case VarInjectionWatchpoint:
@@ -424,7 +420,6 @@
}
case CheckStructure:
- case StructureTransitionWatchpoint:
case InstanceOf:
read(JSCell_structureID);
return;
@@ -453,13 +448,11 @@
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 @@
write(JSCell_indexingType);
write(JSObject_butterfly);
write(Watchpoint_fire);
- clobberizeForAllocation(read, write);
return;
case GetIndexedPropertyStorage:
@@ -508,10 +500,8 @@
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 @@
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 @@
case ThrowReferenceError:
write(SideState);
- clobberizeForAllocation(read, write);
+ read(HeapObjectCount);
+ write(HeapObjectCount);
return;
case CountExecution:
@@ -671,12 +663,6 @@
read(InternalState);
write(InternalState);
return;
-
- case StoreBarrier:
- case StoreBarrierWithNullCheck:
- read(BarrierState);
- write(BarrierState);
- return;
case LastNodeType:
RELEASE_ASSERT_NOT_REACHED();
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.cpp b/Source/JavaScriptCore/dfg/DFGCommon.cpp
index 09ac340..a11d7b8 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCommon.cpp
@@ -33,15 +33,23 @@
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 {
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h
index dbe7ca2..5b08fe4 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.h
+++ b/Source/JavaScriptCore/dfg/DFGCommon.h
@@ -259,6 +259,8 @@
// when you're forcing a crash with diagnostics.
void startCrashing();
+JS_EXPORT_PRIVATE bool isCrashing();
+
} } // namespace JSC::DFG
namespace WTF {
diff --git a/Source/JavaScriptCore/dfg/DFGCommonData.cpp b/Source/JavaScriptCore/dfg/DFGCommonData.cpp
index ad4d09d..d78c0f2 100644
--- a/Source/JavaScriptCore/dfg/DFGCommonData.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCommonData.cpp
@@ -41,8 +41,8 @@
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)
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index d0059a8..39cd8bf 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -104,27 +104,12 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
}
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 @@
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));
diff --git a/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp b/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp
index a7704f4..3155da4 100644
--- a/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp
@@ -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 @@
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)
diff --git a/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h b/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h
index 3e07f9b..b330f0a 100644
--- a/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h
+++ b/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h
@@ -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
@@ -39,26 +39,7 @@
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 @@
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 @@
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 @@
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 @@
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)
+ bool isWatched(WatchpointSet* set)
{
- return m_sets.isStillValid(set);
+ return m_sets.isWatched(set);
}
- bool isStillValid(InlineWatchpointSet& set)
+ bool isWatched(InlineWatchpointSet& set)
{
- return m_inlineSets.isStillValid(&set);
+ return m_inlineSets.isWatched(&set);
}
- bool isStillValid(JSArrayBufferView* view)
+ bool isWatched(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)
- {
- return m_sets.isValidOrMixed(set);
- }
- bool isValidOrMixed(InlineWatchpointSet& set)
- {
- return m_inlineSets.isValidOrMixed(&set);
- }
- bool isValidOrMixed(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
index 0000000..54c1769
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -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
index 0000000..4503d21f
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.h
@@ -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
+
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 1ad8113..4c49417 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -927,7 +927,6 @@
case CheckExecutable:
case CheckStructure:
- case StructureTransitionWatchpoint:
case CheckFunction:
case CheckHasInstance:
case CreateThis:
@@ -1357,7 +1356,7 @@
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())
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 0156c8b..412e35e 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -77,6 +77,16 @@
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 @@
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 @@
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::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 @@
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 @@
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* 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 @@
visitor.appendUnbarrieredReadOnlyPointer(node->structureSet()[i]);
break;
- case StructureTransitionWatchpoint:
case NewObject:
case ArrayifyToStructure:
case NewStringObject:
@@ -858,9 +872,34 @@
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::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)
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index c3a308b..3e596e4 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -170,8 +170,12 @@
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 @@
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 @@
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 @@
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 @@
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 @@
} \
} 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
diff --git a/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
index 1121305..feda66d 100644
--- a/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
@@ -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 @@
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 @@
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 @@
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 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 @@
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::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 @@
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 @@
if (!to->cfaHasVisited)
changed = true;
+ if (verbose)
+ dataLog(" Will revisit: ", changed, "\n");
to->cfaShouldRevisit |= changed;
return changed;
diff --git a/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.h b/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.h
index 48da3aa..9a54623 100644
--- a/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.h
+++ b/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.h
@@ -103,6 +103,9 @@
// 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 @@
// 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 @@
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).
};
diff --git a/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.cpp b/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.cpp
index b3131a4..b2dc4d2 100644
--- a/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.cpp
@@ -68,13 +68,11 @@
} 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;
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 9255394..a238a19 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -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 @@
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 @@
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 @@
return reinterpret_cast<void*>(m_opInfo);
}
- bool hasStructureTransitionData()
+ bool hasTransition()
{
switch (op()) {
case PutStructure:
@@ -1114,10 +1088,10 @@
}
}
- 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 @@
bool hasStructure()
{
switch (op()) {
- case StructureTransitionWatchpoint:
case ArrayifyToStructure:
case NewObject:
case NewStringObject:
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 2575198..8bf72f8 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -158,18 +158,6 @@
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) \
diff --git a/Source/JavaScriptCore/dfg/DFGPlan.cpp b/Source/JavaScriptCore/dfg/DFGPlan.cpp
index c78a307..a6129c3 100644
--- a/Source/JavaScriptCore/dfg/DFGPlan.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPlan.cpp
@@ -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 @@
performBackwardsPropagation(dfg);
performPredictionPropagation(dfg);
performFixup(dfg);
+ performWatchableStructureWatching(dfg);
performInvalidationPointInjection(dfg);
performTypeCheckHoisting(dfg);
@@ -311,6 +313,11 @@
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);
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 1fcb3ab..dd0e387 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -610,7 +610,6 @@
case SetArgument:
case CheckStructure:
case CheckExecutable:
- case StructureTransitionWatchpoint:
case CheckFunction:
case PutStructure:
case TearOffActivation:
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 866cb22..9dc4352 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -279,22 +279,26 @@
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();
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 83b07e8..bed0da1 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -4220,7 +4220,7 @@
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 @@
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::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();
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index da17fb3..337e466 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -3130,7 +3130,7 @@
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(
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index a2965e0..fd4a2d3 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -3739,29 +3739,6 @@
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);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index c0055e4..4d08a1f 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -3852,32 +3852,6 @@
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 @@
}
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);
diff --git a/Source/JavaScriptCore/dfg/DFGStoreBarrierElisionPhase.cpp b/Source/JavaScriptCore/dfg/DFGStoreBarrierElisionPhase.cpp
index 4217552..7f4c16e 100644
--- a/Source/JavaScriptCore/dfg/DFGStoreBarrierElisionPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStoreBarrierElisionPhase.cpp
@@ -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 @@
}
private:
- bool couldCauseGC(Node* node)
- {
- return writesOverlap(m_graph, node, GCState);
- }
-
bool allocatesFreshObject(Node* node)
{
switch (node->op()) {
@@ -104,7 +100,7 @@
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
index 0000000..c3b7a2e
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.cpp
@@ -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)
+
diff --git a/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h
index 10e476c..f9b4b18 100644
--- a/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h
+++ b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h
@@ -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 @@
class StructureAbstractValue {
public:
- StructureAbstractValue()
- : m_structure(0)
- {
- }
-
+ StructureAbstractValue() { }
StructureAbstractValue(Structure* structure)
- : m_structure(structure)
+ : m_set(structure)
{
+ setClobbered(false);
+ }
+ 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;
}
+#if ASSERT_DISABLED
+ void assertIsWatched(Graph&) const { }
+#else
+ void assertIsWatched(Graph&) const;
+#endif
+
+ void clobber();
+ void observeInvalidationPoint() { setClobbered(false); }
+
+ void observeTransition(Structure* from, Structure* to);
+ void observeTransitions(const TransitionVector&);
+
static StructureAbstractValue top()
{
- StructureAbstractValue value;
- value.makeTop();
- return value;
+ StructureAbstractValue result;
+ result.m_set.m_pointer = topValue;
+ return result;
}
- void add(Structure* structure)
- {
- ASSERT(!contains(structure) && !isTop());
- if (m_structure)
- makeTop();
- else
- m_structure = structure;
- }
+ bool isClear() const { return m_set.isEmpty(); }
+ bool isTop() const { return m_set.m_pointer == topValue; }
+ bool isNeitherClearNorTop() const { return !isClear() && !isTop(); }
- 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;
- }
+ // 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 addAll(const StructureAbstractValue& other)
+ bool add(Structure* structure);
+
+ bool merge(const StructureSet& other);
+
+ ALWAYS_INLINE bool merge(const StructureAbstractValue& other)
{
- if (!other.m_structure)
+ if (other.isClear())
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;
- }
-
- bool contains(Structure* structure) const
- {
- if (isTop())
- return true;
- if (m_structure == structure)
- return true;
- return false;
- }
-
- bool isSubsetOf(const StructureSet& other) const
- {
- if (isTop())
- return false;
- if (!m_structure)
- return true;
- return other.contains(m_structure);
- }
-
- bool doesNotContainAnyOtherThan(Structure* structure) const
- {
- if (isTop())
- return false;
- if (!m_structure)
- return true;
- return m_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 isSubsetOf(const StructureAbstractValue& other) const
- {
- if (other.isTop())
- return true;
- if (isTop())
- return false;
- if (m_structure) {
- if (other.m_structure)
- return m_structure == other.m_structure;
- 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.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);
- }
-
- bool hasSingleton() const
- {
- return isNeitherClearNorTop();
- }
-
- Structure* singleton() const
- {
- ASSERT(isNeitherClearNorTop());
- return m_structure;
- }
-
- bool operator==(const StructureAbstractValue& other) const
- {
- return m_structure == other.m_structure;
- }
-
- void dumpInContext(PrintStream& out, DumpContext* context) const
- {
- if (isTop()) {
- out.print("TOP");
- return;
- }
-
- out.print("[");
- if (m_structure)
- out.print(inContext(*m_structure, context));
- out.print("]");
- }
+ // 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().
- void dump(PrintStream& out) const
+ bool contains(Structure* structure) const;
+
+ bool isSubsetOf(const StructureSet& other) const;
+ bool isSubsetOf(const StructureAbstractValue& other) const;
+
+ bool isSupersetOf(const StructureSet& other) const;
+ bool isSupersetOf(const StructureAbstractValue& other) const
{
- dumpInContext(out, 0);
+ return other.isSubsetOf(*this);
}
-
+
+ bool overlaps(const StructureSet& other) const;
+ bool overlaps(const StructureAbstractValue& other) const;
+
private:
- static Structure* topValue() { return reinterpret_cast<Structure*>(1); }
+ static const uintptr_t clobberedFlag = StructureSet::reservedFlag;
+ static const uintptr_t topValue = StructureSet::reservedValue;
+ static const unsigned polymorphismLimit = 10;
+ static const unsigned clobberedSupremacyThreshold = 2;
- // NB. This must have a trivial destructor.
+ void filterSlow(SpeculatedType type);
+ bool mergeSlow(const StructureAbstractValue& other);
- // This can only remember one structure at a time.
- Structure* m_structure;
+ bool equalsSlow(const StructureAbstractValue& other) const;
+
+ void makeTopWhenThin()
+ {
+ ASSERT(m_set.isThin());
+ m_set.m_pointer = topValue;
+ }
+
+ bool mergeNotTop(const StructureSet& other);
+
+ void setClobbered(bool clobbered)
+ {
+ ASSERT(!isTop() || !clobbered);
+ m_set.setReservedFlag(clobbered);
+ }
+
+ StructureSet m_set;
};
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGStructureClobberState.h b/Source/JavaScriptCore/dfg/DFGStructureClobberState.h
new file mode 100644
index 0000000..b8e8a13
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGStructureClobberState.h
@@ -0,0 +1,72 @@
+/*
+ * 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 DFGStructureClobberState_h
+#define DFGStructureClobberState_h
+
+#if ENABLE(DFG_JIT)
+
+#include <wtf/PrintStream.h>
+
+namespace JSC { namespace DFG {
+
+enum StructureClobberState {
+ StructuresAreWatched, // Constants with watchable structures must have those structures.
+ StructuresAreClobbered // Constants with watchable structures could have any structure.
+};
+
+inline StructureClobberState merge(StructureClobberState a, StructureClobberState b)
+{
+ switch (a) {
+ case StructuresAreWatched:
+ return b;
+ case StructuresAreClobbered:
+ return StructuresAreClobbered;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} } // namespace JSC::DFG
+
+namespace WTF {
+
+inline void printInternal(PrintStream& out, JSC::DFG::StructureClobberState state)
+{
+ switch (state) {
+ case JSC::DFG::StructuresAreWatched:
+ out.print("StructuresAreWatched");
+ return;
+ case JSC::DFG::StructuresAreClobbered:
+ out.print("StructuresAreClobbered");
+ return;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGStructureClobberState_h
diff --git a/Source/JavaScriptCore/dfg/DFGTransition.cpp b/Source/JavaScriptCore/dfg/DFGTransition.cpp
new file mode 100644
index 0000000..80d9b99
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGTransition.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 "DFGTransition.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "JSCInlines.h"
+
+namespace JSC { namespace DFG {
+
+void Transition::dumpInContext(PrintStream& out, DumpContext* context) const
+{
+ out.print(pointerDumpInContext(previous, context), " -> ", pointerDumpInContext(next, context));
+}
+
+void Transition::dump(PrintStream& out) const
+{
+ dumpInContext(out, 0);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGTransition.h b/Source/JavaScriptCore/dfg/DFGTransition.h
new file mode 100644
index 0000000..49a6544
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGTransition.h
@@ -0,0 +1,68 @@
+/*
+ * 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 DFGTransition_h
+#define DFGTransition_h
+
+#if ENABLE(DFG_JIT)
+
+#include <wtf/PrintStream.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class Structure;
+struct DumpContext;
+
+namespace DFG {
+
+struct Transition {
+ Structure* previous;
+ Structure* next;
+
+ Transition()
+ : previous(nullptr)
+ , next(nullptr)
+ {
+ }
+
+ Transition(Structure* previous, Structure* next)
+ : previous(previous)
+ , next(next)
+ {
+ }
+
+ void dumpInContext(PrintStream&, DumpContext*) const;
+ void dump(PrintStream&) const;
+};
+
+typedef Vector<Transition, 3> TransitionVector;
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGTransition_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp
index ad509cf..5945315 100644
--- a/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp
@@ -215,8 +215,7 @@
for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
Node* node = block->at(indexInBlock);
switch (node->op()) {
- case CheckStructure:
- case StructureTransitionWatchpoint: {
+ case CheckStructure: {
Node* child = node->child1().node();
if (child->op() != GetLocal)
break;
@@ -285,13 +284,6 @@
noticeStructureCheck(variable, subNode->structureSet());
break;
}
- case StructureTransitionWatchpoint: {
- if (subNode->child1() != source)
- break;
-
- noticeStructureCheck(variable, subNode->structure());
- break;
- }
default:
break;
}
@@ -331,7 +323,6 @@
}
case CheckStructure:
- case StructureTransitionWatchpoint:
case GetByOffset:
case PutByOffset:
case PutStructure:
@@ -386,13 +377,6 @@
noticeStructureCheckAccountingForArrayMode(variable, subNode->structureSet());
break;
}
- case StructureTransitionWatchpoint: {
- if (subNode->child1() != source)
- break;
-
- noticeStructureCheckAccountingForArrayMode(variable, subNode->structure());
- break;
- }
case CheckArray: {
if (subNode->child1() != source)
break;
@@ -503,7 +487,7 @@
noticeStructureCheck(variable, 0);
return;
}
- noticeStructureCheck(variable, set.singletonStructure());
+ noticeStructureCheck(variable, set.onlyStructure());
}
void noticeCheckArray(VariableAccessData* variable, ArrayMode arrayMode)
diff --git a/Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp b/Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp
new file mode 100644
index 0000000..4771a9a
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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 "DFGWatchableStructureWatchingPhase.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGBasicBlockInlines.h"
+#include "DFGGraph.h"
+#include "DFGPhase.h"
+#include "JSCInlines.h"
+
+namespace JSC { namespace DFG {
+
+class WatchableStructureWatchingPhase : public Phase {
+public:
+ WatchableStructureWatchingPhase(Graph& graph)
+ : Phase(graph, "watchable structure watching")
+ {
+ }
+
+ bool run()
+ {
+ // These are pretty dumb, but needed to placate subsequent assertions. We con't actually
+ // have to watch these because there is no way to transition away from it, but they are
+ // watchable and so we will assert if they aren't watched.
+ tryWatch(m_graph.m_vm.stringStructure.get());
+ tryWatch(m_graph.m_vm.getterSetterStructure.get());
+
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+
+ for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
+ Node* node = block->at(nodeIndex);
+
+ switch (node->op()) {
+ case JSConstant:
+ case WeakJSConstant:
+ tryWatch(m_graph.valueOfJSConstant(node));
+ break;
+
+ case CheckFunction:
+ tryWatch(node->function());
+ break;
+
+ case CheckExecutable:
+ tryWatch(node->executable());
+ break;
+
+ case CheckStructure:
+ tryWatch(node->structureSet());
+ break;
+
+ case NewObject:
+ case ArrayifyToStructure:
+ case NewStringObject:
+ tryWatch(node->structure());
+ break;
+
+ case PutStructure:
+ case PhantomPutStructure:
+ case AllocatePropertyStorage:
+ case ReallocatePropertyStorage:
+ RELEASE_ASSERT(node->transition()->previous->transitionWatchpointSetHasBeenInvalidated());
+ tryWatch(node->transition()->next);
+ break;
+
+ case MultiGetByOffset:
+ for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) {
+ GetByIdVariant& variant = node->multiGetByOffsetData().variants[i];
+ tryWatch(variant.specificValue());
+ tryWatch(variant.structureSet());
+ // Don't need to watch anything in the structure chain because that would
+ // have been decomposed into CheckStructure's. Don't need to watch 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];
+ tryWatch(variant.oldStructure());
+ if (variant.kind() == PutByIdVariant::Transition)
+ tryWatch(variant.newStructure());
+ }
+ break;
+
+ case NewArray:
+ case NewArrayBuffer:
+ tryWatch(m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
+ break;
+
+ case NewTypedArray:
+ tryWatch(m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructure(node->typedArrayType()));
+ break;
+
+ case ToString:
+ tryWatch(m_graph.globalObjectFor(node->origin.semantic)->stringObjectStructure());
+ break;
+
+ case CreateActivation:
+ tryWatch(m_graph.globalObjectFor(node->origin.semantic)->activationStructure());
+ break;
+
+ case NewRegexp:
+ tryWatch(m_graph.globalObjectFor(node->origin.semantic)->regExpStructure());
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return true;
+ }
+
+private:
+ void tryWatch(JSValue value)
+ {
+ if (value.isCell())
+ tryWatch(value.asCell());
+ }
+
+ void tryWatch(JSCell* cell)
+ {
+ if (cell)
+ tryWatch(cell->structure());
+ }
+
+ void tryWatch(const StructureSet& set)
+ {
+ for (unsigned i = set.size(); i--;)
+ tryWatch(set[i]);
+ }
+
+ void tryWatch(Structure* structure)
+ {
+ m_graph.watchpoints().consider(structure);
+ }
+};
+
+bool performWatchableStructureWatching(Graph& graph)
+{
+ SamplingRegion samplingRegion("DFG Watchable Structure Watching");
+ return runPhase<WatchableStructureWatchingPhase>(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.h b/Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.h
new file mode 100644
index 0000000..6364d4b
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.h
@@ -0,0 +1,53 @@
+/*
+ * 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 DFGWatchableStructureWatchingPhase_h
+#define DFGWatchableStructureWatchingPhase_h
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+class Graph;
+
+// Set watchpoints on any structures that we know of that are currently watchable. It's
+// somewhat counterintuitive, but this ends up being the cleanest and most effective way
+// of reducing structure checks on terminal structures:
+//
+// - We used to only set watchpoints on watchable structures if we knew that this would
+// remove a structure check. Experiments show that switching from that, to blindly
+// setting watchpoints on all watchable structures, was not a regression.
+//
+// - It makes abstract interpretation a whole lot easier. We just assume that watchable
+// structures are unclobberable without having to do any other logic.
+
+bool performWatchableStructureWatching(Graph&);
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGWatchableStructureWatchingPhase_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp b/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp
index 43e1b2d..99afa4d 100644
--- a/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp
@@ -64,8 +64,6 @@
private:
void handle()
{
- DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, handleEdge);
-
switch (m_node->op()) {
case CompareEqConstant:
case IsUndefined:
@@ -119,13 +117,6 @@
addLazily(jsCast<JSFunction*>(m_node->function())->allocationProfileWatchpointSet());
break;
- case StructureTransitionWatchpoint:
- m_graph.watchpoints().addLazily(
- m_node->origin.semantic,
- m_node->child1()->op() == WeakJSConstant ? BadWeakConstantCacheWatchpoint : BadCacheWatchpoint,
- m_node->structure()->transitionWatchpointSet());
- break;
-
case VariableWatchpoint:
addLazily(m_node->variableWatchpointSet());
break;
@@ -147,26 +138,6 @@
}
}
- void handleEdge(Node*, Edge edge)
- {
- switch (edge.useKind()) {
- case StringObjectUse:
- case StringOrStringObjectUse: {
- Structure* stringObjectStructure = globalObject()->stringObjectStructure();
- Structure* stringPrototypeStructure = stringObjectStructure->storedPrototype().asCell()->structure();
- ASSERT(m_graph.watchpoints().isValidOrMixed(stringPrototypeStructure->transitionWatchpointSet()));
-
- m_graph.watchpoints().addLazily(
- m_node->origin.semantic, NotStringObject,
- stringPrototypeStructure->transitionWatchpointSet());
- break;
- }
-
- default:
- break;
- }
- }
-
void handleMasqueradesAsUndefined()
{
if (m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->origin.semantic))
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index be0233f..252076e 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -63,7 +63,6 @@
case BitLShift:
case BitURShift:
case CheckStructure:
- case StructureTransitionWatchpoint:
case ArrayifyToStructure:
case PutStructure:
case PhantomPutStructure:
diff --git a/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h b/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
index 667e3fb..aa74462 100644
--- a/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
+++ b/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
@@ -91,6 +91,8 @@
macro(V_JITOperation_EC, functionType(voidType, intPtr, intPtr)) \
macro(V_JITOperation_ECb, functionType(voidType, intPtr, intPtr)) \
macro(V_JITOperation_EVwsJ, functionType(voidType, intPtr, intPtr, int64)) \
+ macro(V_JITOperation_J, functionType(voidType, int64)) \
+ macro(V_JITOperation_Z, functionType(voidType, int32)) \
macro(Z_JITOperation_D, functionType(int32, doubleType))
class IntrinsicRepository : public CommonValues {
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index d5336ae..2c0ee68 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -52,6 +52,24 @@
static std::atomic<int> compileCounter;
+#if ASSERT_DISABLED
+NO_RETURN_DUE_TO_CRASH static void ftlUnreachable()
+{
+ CRASH();
+}
+#else
+NO_RETURN_DUE_TO_CRASH static void ftlUnreachable(
+ CodeBlock* codeBlock, BlockIndex blockIndex, unsigned nodeIndex)
+{
+
+ dataLog("Crashing in thought-to-be-unreachable FTL-generated code for ", pointerDump(codeBlock), " at basic block #", blockIndex);
+ if (nodeIndex != UINT_MAX)
+ dataLog(", node @", nodeIndex);
+ dataLog(".\n");
+ CRASH();
+}
+#endif
+
// Using this instead of typeCheck() helps to reduce the load on LLVM, by creating
// significantly less dead code.
#define FTL_TYPE_CHECK(lowValue, highValue, typesPassedThrough, failCondition) do { \
@@ -201,7 +219,7 @@
type = m_out.int64;
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, node, "Bad Phi node result type");
break;
}
m_phis.add(node, buildAlloca(m_out.m_builder, type));
@@ -236,10 +254,12 @@
m_out.appendTo(lowBlock, m_nextLowBlock);
if (Options::ftlCrashes())
- m_out.crashNonTerminal();
+ m_out.trap();
if (!m_highBlock->cfaHasVisited) {
- m_out.crash();
+ if (verboseCompilationEnabled())
+ dataLog("Bailing because CFA didn't reach.\n");
+ crash(m_highBlock->index, UINT_MAX);
return;
}
@@ -257,7 +277,26 @@
bool compileNode(unsigned nodeIndex)
{
if (!m_state.isValid()) {
- m_out.unreachable();
+ if (verboseCompilationEnabled())
+ dataLog("Bailing.\n");
+ crash(m_highBlock->index, m_node->index());
+
+ // Invalidate dominated blocks. Under normal circumstances we would expect
+ // them to be invalidated already. But you can have the CFA become more
+ // precise over time because the structures of objects change on the main
+ // thread. Failing to do this would result in weird crashes due to a value
+ // being used but not defined. Race conditions FTW!
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* target = m_graph.block(blockIndex);
+ if (!target)
+ continue;
+ if (m_graph.m_dominators.dominates(m_highBlock, target)) {
+ if (verboseCompilationEnabled())
+ dataLog("Block ", *target, " will bail also.\n");
+ target->cfaHasVisited = false;
+ }
+ }
+
return false;
}
@@ -401,9 +440,6 @@
case CheckStructure:
compileCheckStructure();
break;
- case StructureTransitionWatchpoint:
- compileStructureTransitionWatchpoint();
- break;
case CheckFunction:
compileCheckFunction();
break;
@@ -638,12 +674,7 @@
case AllocationProfileWatchpoint:
break;
default:
- dataLog("Unrecognized node in FTL backend:\n");
- m_graph.dump(WTF::dataFile(), " ", m_node);
- dataLog("\n");
- dataLog("Full graph dump:\n");
- m_graph.dump();
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend");
break;
}
@@ -677,7 +708,7 @@
m_out.set(lowJSValue(m_node->child1()), destination);
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -703,7 +734,7 @@
setJSValue(m_out.get(source));
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -746,7 +777,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
}
}
@@ -771,7 +802,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
}
}
@@ -834,7 +865,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -876,7 +907,7 @@
{
VariableAccessData* variable = m_node->variableAccessData();
VirtualRegister operand = variable->machineLocal();
- RELEASE_ASSERT(operand.isArgument());
+ DFG_ASSERT(m_graph, m_node, operand.isArgument());
LValue jsValue = m_out.load64(addressFor(operand));
@@ -897,7 +928,7 @@
setJSValue(jsValue);
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -916,7 +947,7 @@
VariableAccessData* variable = m_node->variableAccessData();
AbstractValue& value = m_state.variables().operand(variable->local());
- RELEASE_ASSERT(variable->isCaptured());
+ DFG_ASSERT(m_graph, m_node, variable->isCaptured());
if (isInt32Speculation(value.m_type))
setInt32(m_out.load32(payloadFor(variable->machineLocal())));
@@ -968,7 +999,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad flush format");
break;
}
@@ -1144,7 +1175,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -1218,7 +1249,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -1321,7 +1352,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -1419,7 +1450,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -1470,7 +1501,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -1496,7 +1527,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -1563,7 +1594,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -1655,12 +1686,6 @@
m_out.appendTo(continuation, lastNext);
}
- void compileStructureTransitionWatchpoint()
- {
- addWeakReference(m_node->structure());
- speculateCell(m_node->child1());
- }
-
void compileCheckFunction()
{
LValue cell = lowCell(m_node->child1());
@@ -1729,7 +1754,7 @@
vmCall(m_out.operation(operationEnsureArrayStorage), m_callFrame, cell);
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad array type");
break;
}
@@ -1746,8 +1771,8 @@
{
m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
- Structure* oldStructure = m_node->structureTransitionData().previousStructure;
- Structure* newStructure = m_node->structureTransitionData().newStructure;
+ Structure* oldStructure = m_node->transition()->previous;
+ Structure* newStructure = m_node->transition()->next;
ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType());
ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags());
ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type());
@@ -1803,7 +1828,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
return;
}
}
@@ -1929,7 +1954,7 @@
{
checkArgumentsNotCreated();
- RELEASE_ASSERT(!m_node->origin.semantic.inlineCallFrame);
+ DFG_ASSERT(m_graph, m_node, !m_node->origin.semantic.inlineCallFrame);
setInt32(m_out.add(m_out.load32NonNegative(payloadFor(JSStack::ArgumentCount)), m_out.constInt32(-1)));
}
@@ -1955,7 +1980,7 @@
// FIXME: FTL should support activations.
// https://bugs.webkit.org/show_bug.cgi?id=129576
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Unimplemented");
}
TypedPointer base;
@@ -1992,7 +2017,7 @@
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad array type");
return;
}
}
@@ -2142,7 +2167,7 @@
result = m_out.load32(pointer);
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad element size");
}
if (elementSize(type) < 4) {
@@ -2186,14 +2211,14 @@
result = m_out.loadDouble(pointer);
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad typed array type");
}
setDouble(result);
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad array type");
return;
} }
}
@@ -2299,7 +2324,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad array type");
}
m_out.jump(continuation);
@@ -2392,7 +2417,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
}
switch (elementSize(type)) {
@@ -2409,7 +2434,7 @@
refType = m_out.ref32;
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad element size");
}
} else /* !isInt(type) */ {
LValue value = lowDouble(child3);
@@ -2423,7 +2448,7 @@
refType = m_out.refDouble;
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad typed array type");
}
}
@@ -2447,7 +2472,7 @@
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad array type");
break;
}
}
@@ -2519,7 +2544,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad array type");
return;
}
}
@@ -2577,7 +2602,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad array type");
return;
}
}
@@ -2622,7 +2647,7 @@
Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(
m_node->indexingType());
- RELEASE_ASSERT(structure->indexingType() == m_node->indexingType());
+ DFG_ASSERT(m_graph, m_node, structure->indexingType() == m_node->indexingType());
if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
unsigned numElements = m_node->numChildren();
@@ -2635,7 +2660,7 @@
switch (m_node->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
- CRASH();
+ DFG_CRASH(m_graph, m_node, "Bad indexing type");
break;
case ALL_DOUBLE_INDEXING_TYPES:
@@ -2653,7 +2678,8 @@
break;
default:
- CRASH();
+ DFG_CRASH(m_graph, m_node, "Corrupt indexing type");
+ break;
}
}
@@ -2699,7 +2725,7 @@
Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(
m_node->indexingType());
- RELEASE_ASSERT(structure->indexingType() == m_node->indexingType());
+ DFG_ASSERT(m_graph, m_node, structure->indexingType() == m_node->indexingType());
if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
unsigned numElements = m_node->numConstants();
@@ -2837,21 +2863,19 @@
void compileAllocatePropertyStorage()
{
- StructureTransitionData& data = m_node->structureTransitionData();
LValue object = lowCell(m_node->child1());
-
- setStorage(allocatePropertyStorage(object, data.previousStructure));
+ setStorage(allocatePropertyStorage(object, m_node->transition()->previous));
}
void compileReallocatePropertyStorage()
{
- StructureTransitionData& data = m_node->structureTransitionData();
+ Transition* transition = m_node->transition();
LValue object = lowCell(m_node->child1());
LValue oldStorage = lowStorage(m_node->child2());
setStorage(
reallocatePropertyStorage(
- object, oldStorage, data.previousStructure, data.newStructure));
+ object, oldStorage, transition->previous, transition->next));
}
void compileToString()
@@ -2936,7 +2960,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
}
@@ -3028,7 +3052,7 @@
m_out.operation(operationMakeRope3), m_callFrame, kids[0], kids[1], kids[2]));
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad number of children");
break;
}
m_out.jump(continuation);
@@ -3253,7 +3277,7 @@
}
m_out.appendTo(exit, continuation);
- terminate(BadCache);
+ speculate(BadCache, noValue(), nullptr, m_out.booleanTrue);
m_out.unreachable();
m_out.appendTo(continuation, lastNext);
@@ -3325,7 +3349,7 @@
}
m_out.appendTo(exit, continuation);
- terminate(BadCache);
+ speculate(BadCache, noValue(), nullptr, m_out.booleanTrue);
m_out.unreachable();
m_out.appendTo(continuation, lastNext);
@@ -3444,7 +3468,7 @@
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kinds");
}
void compileCompareEqConstant()
@@ -3537,7 +3561,7 @@
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kinds");
}
void compileCompareStrictEqConstant()
@@ -3673,7 +3697,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
@@ -3719,7 +3743,7 @@
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
}
@@ -3772,11 +3796,11 @@
}
case SwitchString:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Unimplemented");
break;
}
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad switch kind");
}
void compileReturn()
@@ -3958,7 +3982,7 @@
speculate(m_node->child1());
#endif
}
-
+
LValue didOverflowStack()
{
// This does a very simple leaf function analysis. The invariant of FTL call
@@ -4233,7 +4257,7 @@
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kinds");
}
void compareEqObjectOrOtherToObject(Edge leftChild, Edge rightChild)
@@ -4512,7 +4536,7 @@
return m_out.phi(m_out.boolean, fastResult, slowResult);
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
return 0;
}
}
@@ -4759,7 +4783,8 @@
void terminate(ExitKind kind)
{
- speculate(kind, noValue(), 0, m_out.booleanTrue);
+ speculate(kind, noValue(), nullptr, m_out.booleanTrue);
+ m_state.setIsValid(false);
}
void typeCheck(
@@ -4815,7 +4840,7 @@
return result;
}
- RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecInt32));
+ DFG_ASSERT(m_graph, m_node, !(m_state.forNode(edge).m_type & SpecInt32));
terminate(Uncountable);
return m_out.int32Zero;
}
@@ -4823,7 +4848,7 @@
enum Int52Kind { StrictInt52, Int52 };
LValue lowInt52(Edge edge, Int52Kind kind)
{
- RELEASE_ASSERT(edge.useKind() == Int52RepUse);
+ DFG_ASSERT(m_graph, m_node, edge.useKind() == Int52RepUse);
LoweredNodeValue value;
@@ -4849,7 +4874,7 @@
break;
}
- RELEASE_ASSERT(!m_state.forNode(edge).m_type);
+ DFG_ASSERT(m_graph, m_node, !m_state.forNode(edge).m_type);
terminate(Uncountable);
return m_out.int64Zero;
}
@@ -4885,7 +4910,7 @@
case StrictInt52:
return Int52;
}
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Bad use kind");
return Int52;
}
@@ -4916,7 +4941,7 @@
return uncheckedValue;
}
- RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecCell));
+ DFG_ASSERT(m_graph, m_node, !(m_state.forNode(edge).m_type & SpecCell));
terminate(Uncountable);
return m_out.intPtrZero;
}
@@ -4985,20 +5010,19 @@
return result;
}
- RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecBoolean));
+ DFG_ASSERT(m_graph, m_node, !(m_state.forNode(edge).m_type & SpecBoolean));
terminate(Uncountable);
return m_out.booleanFalse;
}
LValue lowDouble(Edge edge)
{
- RELEASE_ASSERT(isDouble(edge.useKind()));
+ DFG_ASSERT(m_graph, m_node, isDouble(edge.useKind()));
LoweredNodeValue value = m_doubleValues.get(edge.node());
if (isValid(value))
return value.value();
-
- RELEASE_ASSERT(!m_state.forNode(edge).m_type);
+ DFG_ASSERT(m_graph, m_node, !m_state.forNode(edge).m_type);
terminate(Uncountable);
return m_out.doubleZero;
}
@@ -5006,8 +5030,8 @@
LValue lowJSValue(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
{
ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse);
- RELEASE_ASSERT(!isDouble(edge.useKind()));
- RELEASE_ASSERT(edge.useKind() != Int52RepUse);
+ DFG_ASSERT(m_graph, m_node, !isDouble(edge.useKind()));
+ DFG_ASSERT(m_graph, m_node, edge.useKind() != Int52RepUse);
if (edge->hasConstant())
return m_out.constInt64(JSValue::encode(m_graph.valueOfJSConstant(edge.node())));
@@ -5030,7 +5054,7 @@
return result;
}
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Value not defined");
return 0;
}
@@ -5342,8 +5366,7 @@
speculateMisc(edge);
break;
default:
- dataLog("Unsupported speculation use kind: ", edge.useKind(), "\n");
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Unsupported speculation use kind");
}
}
@@ -5404,7 +5427,7 @@
switch (arrayMode.arrayClass()) {
case Array::OriginalArray:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Unexpected original array");
return 0;
case Array::Array:
@@ -5424,7 +5447,7 @@
m_out.constInt8(arrayMode.shapeMask()));
}
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Corrupt array class");
}
default:
@@ -5567,7 +5590,7 @@
Structure* stringObjectStructure =
m_graph.globalObjectFor(m_node->origin.semantic)->stringObjectStructure();
- if (m_state.forNode(edge).m_currentKnownStructure.isSubsetOf(StructureSet(stringObjectStructure)))
+ if (m_state.forNode(edge).m_structure.isSubsetOf(StructureSet(stringObjectStructure)))
return;
speculate(
@@ -5782,9 +5805,10 @@
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Exception check continuation"));
+ LValue exception = m_out.load64(m_out.absolute(vm().addressOfException()));
+
m_out.branch(
- m_out.notZero64(m_out.load64(m_out.absolute(vm().addressOfException()))),
- rarely(m_handleExceptions), usually(continuation));
+ m_out.notZero64(exception), rarely(m_handleExceptions), usually(continuation));
m_out.appendTo(continuation);
}
@@ -5871,10 +5895,8 @@
break;
}
- if (Options::validateFTLOSRExitLiveness()) {
- dataLog("Expected r", operand, " to be available but it wasn't.\n");
- RELEASE_ASSERT_NOT_REACHED();
- }
+ if (Options::validateFTLOSRExitLiveness())
+ DFG_CRASH(m_graph, m_node, toCString("Expected r", operand, " to be available but it wasn't.").data());
// This means that the DFG's DCE proved that the value is dead in bytecode
// even though the bytecode liveness analysis thinks it's live. This is
@@ -5979,10 +6001,7 @@
return;
}
- startCrashing();
- dataLog("Cannot find value for node: ", node, " while compiling exit at ", exit.m_codeOrigin, " in node ", m_node, "\n");
- m_graph.dump();
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, toCString("Cannot find value for node: ", node).data());
}
bool tryToSetConstantExitArgument(OSRExit& exit, unsigned index, Node* node)
@@ -6060,7 +6079,7 @@
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_graph, m_node, "Corrupt int52 kind");
}
void setJSValue(Node* node, LValue value)
{
@@ -6187,6 +6206,25 @@
return addressFor(operand, TagOffset);
}
+ void crash(BlockIndex blockIndex, unsigned nodeIndex)
+ {
+#if ASSERT_DISABLED
+ m_out.call(m_out.operation(ftlUnreachable));
+ UNUSED_PARAM(blockIndex);
+ UNUSED_PARAM(nodeIndex);
+#else
+ m_out.call(
+ m_out.intToPtr(
+ m_out.constIntPtr(ftlUnreachable),
+ pointerType(
+ functionType(
+ m_out.voidType, m_out.intPtr, m_out.int32, m_out.int32))),
+ m_out.constIntPtr(codeBlock()), m_out.constInt32(blockIndex),
+ m_out.constInt32(nodeIndex));
+#endif
+ m_out.unreachable();
+ }
+
VM& vm() { return m_graph.m_vm; }
CodeBlock* codeBlock() { return m_graph.m_codeBlock; }
diff --git a/Source/JavaScriptCore/ftl/FTLOutput.cpp b/Source/JavaScriptCore/ftl/FTLOutput.cpp
index 986d374..55b30ec 100644
--- a/Source/JavaScriptCore/ftl/FTLOutput.cpp
+++ b/Source/JavaScriptCore/ftl/FTLOutput.cpp
@@ -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
@@ -138,11 +138,6 @@
constInt32(notTakenWeight.scaleToTotal(total))));
}
-void Output::crashNonTerminal()
-{
- call(intToPtr(constIntPtr(abort), pointerType(functionType(voidType))));
-}
-
} } // namespace JSC::FTL
#endif // ENABLE(FTL_JIT)
diff --git a/Source/JavaScriptCore/ftl/FTLOutput.h b/Source/JavaScriptCore/ftl/FTLOutput.h
index f71b9c6..c70d8cd 100644
--- a/Source/JavaScriptCore/ftl/FTLOutput.h
+++ b/Source/JavaScriptCore/ftl/FTLOutput.h
@@ -401,14 +401,6 @@
call(trapIntrinsic());
}
- void crashNonTerminal();
-
- void crash()
- {
- crashNonTerminal();
- unreachable();
- }
-
ValueFromBlock anchor(LValue value)
{
return ValueFromBlock(value, m_block);
diff --git a/Source/JavaScriptCore/jit/JITOperations.h b/Source/JavaScriptCore/jit/JITOperations.h
index c36acec..78ea5fb 100644
--- a/Source/JavaScriptCore/jit/JITOperations.h
+++ b/Source/JavaScriptCore/jit/JITOperations.h
@@ -171,6 +171,8 @@
typedef void JIT_OPERATION (*V_JITOperation_EVwsJ)(ExecState*, VariableWatchpointSet*, EncodedJSValue);
typedef void JIT_OPERATION (*V_JITOperation_EZ)(ExecState*, int32_t);
typedef void JIT_OPERATION (*V_JITOperation_EVm)(ExecState*, VM*);
+typedef void JIT_OPERATION (*V_JITOperation_J)(EncodedJSValue);
+typedef void JIT_OPERATION (*V_JITOperation_Z)(int32_t);
typedef char* JIT_OPERATION (*P_JITOperation_E)(ExecState*);
typedef char* JIT_OPERATION (*P_JITOperation_EC)(ExecState*, JSCell*);
typedef char* JIT_OPERATION (*P_JITOperation_ECli)(ExecState*, CallLinkInfo*);
diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp
index 13a7188..d66995c 100644
--- a/Source/JavaScriptCore/jsc.cpp
+++ b/Source/JavaScriptCore/jsc.cpp
@@ -94,6 +94,17 @@
namespace {
+NO_RETURN_WITH_VALUE static void jscExit(int status)
+{
+#if ENABLE(DFG_JIT)
+ if (DFG::isCrashing()) {
+ for (;;)
+ pause();
+ }
+#endif // ENABLE(DFG_JIT)
+ exit(status);
+}
+
class Element;
class ElementHandleOwner;
class Masuqerader;
@@ -890,7 +901,7 @@
EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
{
- exit(EXIT_SUCCESS);
+ jscExit(EXIT_SUCCESS);
#if COMPILER(MSVC) && OS(WINCE)
// Without this, Visual Studio will complain that this method does not return a value.
@@ -1010,7 +1021,7 @@
ecore_shutdown();
#endif
- return res;
+ jscExit(res);
}
static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
@@ -1154,7 +1165,7 @@
fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
fprintf(stderr, "\n");
- exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
+ jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
}
void CommandLine::parseArguments(int argc, char** argv)
@@ -1243,7 +1254,7 @@
if (needToDumpOptions)
JSC::Options::dumpAllOptions(stderr);
if (needToExit)
- exit(EXIT_SUCCESS);
+ jscExit(EXIT_SUCCESS);
}
int jscmain(int argc, char** argv)
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index e9d04e4..9657371 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 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
@@ -370,6 +370,22 @@
{
return m_transitionWatchpointSet.isStillValid();
}
+
+ bool dfgShouldWatchIfPossible() const
+ {
+ // FIXME: We would like to not watch things that are unprofitable to watch, like
+ // dictionaries. Unfortunately, we can't do such things: a dictionary could get flattened,
+ // in which case it will start to appear watchable and so the DFG will think that it is
+ // watching it. We should come up with a comprehensive story for not watching things that
+ // aren't profitable to watch.
+ // https://bugs.webkit.org/show_bug.cgi?id=133625
+ return true;
+ }
+
+ bool dfgShouldWatch() const
+ {
+ return dfgShouldWatchIfPossible() && transitionWatchpointSetIsStillValid();
+ }
void addTransitionWatchpoint(Watchpoint* watchpoint) const
{
diff --git a/Source/JavaScriptCore/tests/stress/arrayify-to-structure-contradiction.js b/Source/JavaScriptCore/tests/stress/arrayify-to-structure-contradiction.js
new file mode 100644
index 0000000..22c8019
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrayify-to-structure-contradiction.js
@@ -0,0 +1,16 @@
+function foo(array, v, p) {
+ array[0] = 10;
+ if (p)
+ v = "hello";
+ array[0] = v;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 100000; ++i) {
+ var array = [42];
+ foo(array, 43, false);
+ if (array[0] != 43)
+ throw "Error: bad result: " + array;
+}
+
diff --git a/Source/JavaScriptCore/tests/stress/ftl-getmyargumentslength-inline.js b/Source/JavaScriptCore/tests/stress/ftl-getmyargumentslength-inline.js
new file mode 100644
index 0000000..5180634
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/ftl-getmyargumentslength-inline.js
@@ -0,0 +1,9 @@
+function foo(){
+ return arguments.length;
+}
+
+for (var i = 0; i < 100000; ++i) {
+ var r = foo(11, 12, 13, 18, 19, 20);
+ if (r != 6) throw "Error: "+r;
+}
+
diff --git a/Source/JavaScriptCore/tests/stress/ftl-library-exception.js b/Source/JavaScriptCore/tests/stress/ftl-library-exception.js
new file mode 100644
index 0000000..41a9e34
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/ftl-library-exception.js
@@ -0,0 +1,21 @@
+function foo(d){
+ return Date.prototype.getTimezoneOffset.call(d);
+}
+
+noInline(foo);
+
+var x;
+var count = 100000;
+var z = 0;
+for (var i = 0 ; i < count; i++){
+ try {
+ var q = foo(i < count - 10 ? new Date() : "a");
+ x = false;
+ z = q;
+ } catch (e) {
+ x = true;
+ }
+}
+
+if (!x)
+ throw "bad result: "+ x;
diff --git a/Source/JavaScriptCore/tests/stress/ftl-library-inline-gettimezoneoffset.js b/Source/JavaScriptCore/tests/stress/ftl-library-inline-gettimezoneoffset.js
new file mode 100644
index 0000000..8df8b12
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/ftl-library-inline-gettimezoneoffset.js
@@ -0,0 +1,16 @@
+function foo(x, d){
+ return x + d.getTimezoneOffset();
+}
+
+noInline(foo);
+
+var d = new Date();
+var expected = foo(0, d);
+var count = 1000000;
+var result = 0;
+for (var i = 0 ; i < count; i++){
+ result += foo(0, d);
+}
+
+if (result != count * expected)
+ throw "Error: bad result: " + result;
diff --git a/Source/JavaScriptCore/tests/stress/ftl-library-inlining-exceptions-dataview.js b/Source/JavaScriptCore/tests/stress/ftl-library-inlining-exceptions-dataview.js
new file mode 100644
index 0000000..f41b9ce
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/ftl-library-inlining-exceptions-dataview.js
@@ -0,0 +1,26 @@
+function foo(d){
+ return d.getInt8(42);
+}
+
+noInline(foo);
+
+var d = new DataView(new ArrayBuffer(43));
+d.setInt8(42, 43);
+for (var i = 0; i < 100000; ++i) {
+ var result = foo(d);
+ if (result != 43)
+ throw "Error: bad result: " + result;
+}
+
+for (var i = 0; i < 10; ++i) {
+ var didThrow = false;
+ try {
+ foo(new DataView(new ArrayBuffer(42)));
+ } catch (e) {
+ didThrow = true;
+ if (e.message.indexOf("Out of bounds") < 0)
+ throw "Error: bad exception: " + e.message;
+ }
+ if (!didThrow)
+ throw "Error: did not throw";
+}
diff --git a/Source/JavaScriptCore/tests/stress/ftl-library-inlining-exceptions.js b/Source/JavaScriptCore/tests/stress/ftl-library-inlining-exceptions.js
new file mode 100644
index 0000000..0b6516bc
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/ftl-library-inlining-exceptions.js
@@ -0,0 +1,19 @@
+function foo(d){
+ return Date.prototype.getTimezoneOffset.call(d);
+}
+
+noInline(foo);
+
+var x;
+var count = 100000;
+for (var i = 0 ; i < count; i++){
+ try {
+ foo(i < count - 1000 ? new Date() : "a");
+ x = false;
+ } catch (e) {
+ x = true;
+ }
+}
+
+if (!x)
+ throw "bad result: "+ x;
\ No newline at end of file
diff --git a/Source/JavaScriptCore/tests/stress/ftl-library-inlining-loops.js b/Source/JavaScriptCore/tests/stress/ftl-library-inlining-loops.js
new file mode 100644
index 0000000..160fcb9
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/ftl-library-inlining-loops.js
@@ -0,0 +1,28 @@
+function foo(){
+ var count = 100;
+ var d = new DataView(new ArrayBuffer(count));
+
+ for (var i = 0; i < count / 4; i++){
+ d.setInt32(i, i);
+ }
+
+ for (var i = 0; i < count; i++){
+ d.setInt8(i, i);
+ }
+ var result = 0;
+ for (var i = 0; i < count; i++){
+ result += d.getInt8(i);
+ }
+ return result;
+}
+
+noInline(foo);
+
+var r = 0;
+for (var i = 0 ; i < 50000; i++){
+ r += foo();
+}
+
+if (r != 247500000)
+ throw "Bad result: " + r;
+
diff --git a/Source/JavaScriptCore/tests/stress/ftl-library-inlining-random.js b/Source/JavaScriptCore/tests/stress/ftl-library-inlining-random.js
new file mode 100644
index 0000000..4b67803
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/ftl-library-inlining-random.js
@@ -0,0 +1,11 @@
+function foo(x){
+ return Math.random(x);
+}
+
+noInline(foo);
+
+var x = 0;
+
+for (var i = 0 ; i < 100000; i++){
+ x = foo(i);
+}
diff --git a/Source/JavaScriptCore/tests/stress/ftl-library-substring.js b/Source/JavaScriptCore/tests/stress/ftl-library-substring.js
new file mode 100644
index 0000000..2bc0532
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/ftl-library-substring.js
@@ -0,0 +1,15 @@
+function foo(i, x){
+ return x.substring( 2 , 5);
+}
+
+noInline(foo);
+
+var x = "";
+
+for (var i = 0 ; i < 100000; i++){
+ x = foo(i, "lkajsx");
+}
+
+if (x != "ajs")
+ throw "Error: bad substring: "+ x;
+
diff --git a/Source/JavaScriptCore/tests/stress/multi-put-by-offset-multiple-transitions.js b/Source/JavaScriptCore/tests/stress/multi-put-by-offset-multiple-transitions.js
new file mode 100644
index 0000000..99987ef
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/multi-put-by-offset-multiple-transitions.js
@@ -0,0 +1,30 @@
+function foo(o) {
+ o.x = 1;
+ o.y = 2;
+ o.a = 3;
+ o.b = 4;
+ o.c = 5;
+ o.d = 6;
+ o.e = 7;
+ o.f = 8;
+ o.g = 9;
+ o.h = 10;
+ o.i = 11;
+}
+
+noInline(foo);
+
+function Foo() {
+ foo(this);
+}
+
+var result = 0;
+
+for (var i = 0; i < 100000; ++i) {
+ foo({f:42});
+ result += (new Foo()).x;
+}
+
+if (result != 100000)
+ throw "Bad result: " + result;
+
diff --git a/Source/JavaScriptCore/tests/stress/throw-from-ftl-in-loop.js b/Source/JavaScriptCore/tests/stress/throw-from-ftl-in-loop.js
new file mode 100644
index 0000000..b87cc8e
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/throw-from-ftl-in-loop.js
@@ -0,0 +1,13 @@
+var didThrow = false;
+try {
+ (function() {
+ for (var i = 0; i < 1000000; ++i) { }
+ throw 42;
+ })();
+} catch (e) {
+ if (e != 42)
+ throw "Error: bad result: " + e;
+ didThrow = true;
+}
+if (!didThrow)
+ throw "Error: should have thrown but didn't.";
diff --git a/Source/JavaScriptCore/tests/stress/throw-from-ftl.js b/Source/JavaScriptCore/tests/stress/throw-from-ftl.js
new file mode 100644
index 0000000..aac2e9e
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/throw-from-ftl.js
@@ -0,0 +1,25 @@
+function foo(p) {
+ var o = {f:42};
+ if (p)
+ throw o;
+ return o;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 100000; ++i) {
+ var o = foo(false);
+ if (o.f != 42)
+ throw "Error: bad result: " + o.f;
+}
+
+var didThrow = false;
+try {
+ foo(true);
+} catch (e) {
+ if (e.f != 42)
+ throw "Error: bad result in catch: " + o.f;
+ didThrow = true;
+}
+if (!didThrow)
+ throw "Error: should have thrown but didn't.";
diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog
index b1b697a..29f322f 100644
--- a/Source/WTF/ChangeLog
+++ b/Source/WTF/ChangeLog
@@ -1,5 +1,20 @@
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.
+
+ * wtf/Bag.h:
+ (WTF::Bag::Node::Node):
+ (WTF::Bag::add):
+
+2014-07-22 Filip Pizlo <fpizlo@apple.com>
+
Merge r168635, r168780, r169005, r169014, and r169143 from ftlopt.
2014-05-20 Filip Pizlo <fpizlo@apple.com>
diff --git a/Source/WTF/wtf/Bag.h b/Source/WTF/wtf/Bag.h
index 6cc713e..2bc2572 100644
--- a/Source/WTF/wtf/Bag.h
+++ b/Source/WTF/wtf/Bag.h
@@ -34,6 +34,12 @@
class Node {
WTF_MAKE_FAST_ALLOCATED;
public:
+ template<typename... Args>
+ Node(Args... args)
+ : m_item(args...)
+ {
+ }
+
T m_item;
Node* m_next;
};
@@ -53,9 +59,10 @@
}
}
- T* add()
+ template<typename... Args>
+ T* add(Args... args)
{
- Node* newNode = new Node;
+ Node* newNode = new Node(args...);
newNode->m_next = m_head;
m_head = newNode;
return &newNode->m_item;