WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
almoster doner
blah.patch (text/plain), 190.41 KB, created by
Filip Pizlo
on 2014-06-01 11:36:46 PDT
(
hide
)
Description:
almoster doner
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2014-06-01 11:36:46 PDT
Size:
190.41 KB
patch
obsolete
>Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 169515) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,282 @@ >+2014-06-01 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 NOBODY (OOPS!). >+ >+ 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. >+ >+ Still a work in progress. >+ >+ * CMakeLists.txt: >+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * bytecode/StructureSet.cpp: >+ (JSC::StructureSet::clear): >+ (JSC::StructureSet::remove): >+ (JSC::StructureSet::filter): >+ (JSC::StructureSet::copyFrom): >+ * bytecode/StructureSet.h: >+ (JSC::StructureSet::StructureSet): >+ (JSC::StructureSet::isEmpty): >+ (JSC::StructureSet::genericFilter): >+ (JSC::StructureSet::ContainsOutOfLine::ContainsOutOfLine): >+ (JSC::StructureSet::ContainsOutOfLine::operator()): >+ (JSC::StructureSet::deleteStructureListIfNecessary): >+ (JSC::StructureSet::setEmpty): >+ (JSC::StructureSet::getReservedFlag): >+ (JSC::StructureSet::setReservedFlag): >+ * dfg/DFGAbstractInterpreter.h: >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::booleanResult): >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::verifyEdge): >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::forAllValues): >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::clobberStructures): >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransition): >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransitions): >+ (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/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::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): >+ * dfg/DFGGraph.cpp: >+ (JSC::DFG::Graph::~Graph): >+ (JSC::DFG::Graph::dump): >+ (JSC::DFG::Graph::tryGetFoldableView): >+ (JSC::DFG::Graph::visitChildren): >+ (JSC::DFG::Graph::assertIsWatched): >+ * dfg/DFGGraph.h: >+ (JSC::DFG::Graph::convertToConstant): >+ (JSC::DFG::Graph::masqueradesAsUndefinedWatchpointIsStillValid): >+ (JSC::DFG::Graph::addStructureTransitionData): Deleted. >+ * 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::StructureAbstractValue): >+ (JSC::DFG::StructureAbstractValue::operator=): >+ (JSC::DFG::StructureAbstractValue::makeTop): >+ (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::mergeNotTop): >+ (JSC::DFG::StructureAbstractValue::filter): >+ (JSC::DFG::StructureAbstractValue::contains): >+ (JSC::DFG::StructureAbstractValue::isSubsetOf): >+ (JSC::DFG::StructureAbstractValue::isSupersetOf): >+ (JSC::DFG::StructureAbstractValue::overlaps): >+ (JSC::DFG::StructureAbstractValue::operator==): >+ (JSC::DFG::StructureAbstractValue::dumpInContext): >+ (JSC::DFG::StructureAbstractValue::dump): >+ * dfg/DFGStructureAbstractValue.h: >+ (JSC::DFG::StructureAbstractValue::StructureAbstractValue): >+ (JSC::DFG::StructureAbstractValue::clear): >+ (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::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::makeTop): Deleted. >+ (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::filter): 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::operator==): Deleted. >+ (JSC::DFG::StructureAbstractValue::dumpInContext): Deleted. >+ (JSC::DFG::StructureAbstractValue::dump): Deleted. >+ (JSC::DFG::StructureAbstractValue::topValue): Deleted. >+ * 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): >+ * ftl/FTLCapabilities.cpp: >+ (JSC::FTL::canCompile): >+ * ftl/FTLIntrinsicRepository.h: >+ * ftl/FTLLowerDFGToLLVM.cpp: >+ (JSC::FTL::LowerDFGToLLVM::compileNode): >+ (JSC::FTL::LowerDFGToLLVM::compilePutStructure): >+ (JSC::FTL::LowerDFGToLLVM::compileAllocatePropertyStorage): >+ (JSC::FTL::LowerDFGToLLVM::compileReallocatePropertyStorage): >+ (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): >+ (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): >+ (JSC::FTL::LowerDFGToLLVM::terminate): >+ (JSC::FTL::LowerDFGToLLVM::speculateStringObjectForStructureID): >+ (JSC::FTL::LowerDFGToLLVM::callCheck): >+ (JSC::FTL::LowerDFGToLLVM::compileStructureTransitionWatchpoint): Deleted. >+ * jit/JITOperations.h: >+ * jsc.cpp: >+ (WTF::jscExit): >+ (functionQuit): >+ (main): >+ (printUsageStatement): >+ (CommandLine::parseArguments): >+ * 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-05-21 Filip Pizlo <fpizlo@apple.com> > > [ftlopt] DFG::clobberize should be blind to the effects of GC >Index: Source/JavaScriptCore/CMakeLists.txt >=================================================================== >--- Source/JavaScriptCore/CMakeLists.txt (revision 169200) >+++ Source/JavaScriptCore/CMakeLists.txt (working copy) >@@ -192,9 +192,11 @@ set(JavaScriptCore_SOURCES > dfg/DFGStaticExecutionCountEstimationPhase.cpp > dfg/DFGStoreBarrierElisionPhase.cpp > dfg/DFGStrengthReductionPhase.cpp >+ dfg/DFGStructureAbstractValue.cpp > dfg/DFGThreadData.cpp > dfg/DFGThunks.cpp > dfg/DFGTierUpCheckInjectionPhase.cpp >+ dfg/DFGTransition.cpp > dfg/DFGTypeCheckHoistingPhase.cpp > dfg/DFGUnificationPhase.cpp > dfg/DFGUseKind.cpp >@@ -205,6 +207,7 @@ set(JavaScriptCore_SOURCES > dfg/DFGVariableEvent.cpp > dfg/DFGVariableEventStream.cpp > dfg/DFGVirtualRegisterAllocationPhase.cpp >+ dfg/DFGWatchableStructureWatchingPhase.cpp > dfg/DFGWatchpointCollectionPhase.cpp > dfg/DFGWorklist.cpp > >Index: Source/JavaScriptCore/jsc.cpp >=================================================================== >--- Source/JavaScriptCore/jsc.cpp (revision 169200) >+++ Source/JavaScriptCore/jsc.cpp (working copy) >@@ -93,6 +93,15 @@ using namespace WTF; > > namespace { > >+NO_RETURN_WITH_VALUE static void jscExit(int status) >+{ >+ if (DFG::isCrashing()) { >+ for (;;) >+ pause(); >+ } >+ exit(status); >+} >+ > class Element; > class ElementHandleOwner; > class Masuqerader; >@@ -885,7 +894,7 @@ EncodedJSValue JSC_HOST_CALL functionTra > > 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. >@@ -1012,7 +1021,7 @@ int main(int argc, char** argv) > ecore_shutdown(); > #endif > >- return res; >+ jscExit(res); > } > > static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump) >@@ -1156,7 +1165,7 @@ static NO_RETURN void printUsageStatemen > 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) >@@ -1245,7 +1254,7 @@ void CommandLine::parseArguments(int arg > if (needToDumpOptions) > JSC::Options::dumpAllOptions(stderr); > if (needToExit) >- exit(EXIT_SUCCESS); >+ jscExit(EXIT_SUCCESS); > } > > int jscmain(int argc, char** argv) >Index: Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj >=================================================================== >--- Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (revision 169200) >+++ Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (working copy) >@@ -443,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" /> >@@ -459,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="..\heap\BlockAllocator.cpp" /> >@@ -1025,6 +1028,7 @@ > <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" /> >@@ -1037,6 +1041,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" /> >Index: Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >=================================================================== >--- Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (revision 169200) >+++ Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (working copy) >@@ -353,6 +353,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 */; }; >@@ -495,6 +496,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 +531,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 */; }; >@@ -2160,6 +2165,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>"; }; >@@ -2313,6 +2319,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>"; }; >@@ -2348,6 +2356,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>"; }; >@@ -4806,6 +4816,7 @@ > 2ACCF3DD185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h */, > 0FC20CB31852E2C600C9E954 /* DFGStrengthReductionPhase.cpp */, > 0FC20CB41852E2C600C9E954 /* DFGStrengthReductionPhase.h */, >+ 0F893BDA1936E23C001211F4 /* DFGStructureAbstractValue.cpp */, > 0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */, > 0F2FCCF718A60070001A27F8 /* DFGThreadData.cpp */, > 0F2FCCF818A60070001A27F8 /* DFGThreadData.h */, >@@ -4817,6 +4828,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 */, >@@ -4838,6 +4851,8 @@ > 0F2BDC431522801700CD8910 /* DFGVariableEventStream.h */, > 0FFFC95314EF909500C72532 /* DFGVirtualRegisterAllocationPhase.cpp */, > 0FFFC95414EF909500C72532 /* DFGVirtualRegisterAllocationPhase.h */, >+ 0FD2D4FC192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.cpp */, >+ 0FD2D4FD192FEE5800A178BF /* DFGWatchableStructureWatchingPhase.h */, > 0FC97F3B18202119002C9B26 /* DFGWatchpointCollectionPhase.cpp */, > 0FC97F3C18202119002C9B26 /* DFGWatchpointCollectionPhase.h */, > 0FDB2CE5174830A2007B3C1B /* DFGWorklist.cpp */, >@@ -5776,6 +5791,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 */, >@@ -5817,6 +5833,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 */, >@@ -6956,6 +6973,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 */, >@@ -6984,6 +7002,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 */, >@@ -7174,6 +7193,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 */, >Index: Source/JavaScriptCore/bytecode/StructureSet.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/StructureSet.cpp (revision 169200) >+++ Source/JavaScriptCore/bytecode/StructureSet.cpp (working copy) >@@ -47,7 +47,7 @@ StructureSet& StructureSet::operator=(co > void StructureSet::clear() > { > deleteStructureListIfNecessary(); >- set(0, true); >+ setEmpty(); > } > > bool StructureSet::add(Structure* structure) >@@ -75,7 +75,7 @@ bool StructureSet::remove(Structure* str > { > if (isThin()) { > if (singleStructure() == structure) { >- set(0, true); >+ setEmpty(); > return true; > } > return false; >@@ -88,7 +88,7 @@ bool StructureSet::remove(Structure* str > list->list()[i] = list->list()[--list->m_length]; > if (!list->m_length) { > OutOfLineList::destroy(list); >- set(0, true); >+ setEmpty(); > } > return true; > } >@@ -144,23 +144,8 @@ void StructureSet::filter(const Structur > return; > } > >- if (isThin()) { >- if (!singleStructure()) >- return; >- if (other.containsOutOfLine(singleStructure())) >- return; >- 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(); >+ ContainsOutOfLine containsOutOfLine(other); >+ genericFilter(containsOutOfLine); > } > > void StructureSet::exclude(const StructureSet& other) >@@ -323,8 +308,10 @@ bool StructureSet::containsOutOfLine(Str > > void StructureSet::copyFrom(const StructureSet& other) > { >- if (other.isThin()) { >+ if (other.isThin() || other.m_pointer == reservedValue) { >+ bool value = getReservedFlag(); > m_pointer = other.m_pointer; >+ setReservedFlag(value); > return; > } > >Index: Source/JavaScriptCore/bytecode/StructureSet.h >=================================================================== >--- Source/JavaScriptCore/bytecode/StructureSet.h (revision 169200) >+++ Source/JavaScriptCore/bytecode/StructureSet.h (working copy) >@@ -33,11 +33,15 @@ > > namespace JSC { > >+namespace DFG { >+class StructureAbstractValue; >+} >+ > class StructureSet { > public: > StructureSet() > { >- set(0, true); >+ setEmpty(); > } > > StructureSet(Structure* structure) >@@ -67,7 +71,10 @@ public: > > bool isEmpty() const > { >- return isThin() && !singleStructure(); >+ bool result = isThin() && !singleStructure(); >+ if (result) >+ ASSERT(m_pointer != reservedValue); >+ return result; > } > > bool add(Structure*); >@@ -78,6 +85,28 @@ public: > 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; >+ } >+ >+ 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]; >+ } >+ if (!list->m_length) >+ clear(); >+ } >+ > bool isSubsetOf(const StructureSet&) const; > bool isSupersetOf(const StructureSet& other) const > { >@@ -124,15 +153,33 @@ public: > void dump(PrintStream&) const; > > private: >+ friend class DFG::StructureAbstractValue; >+ > static const uintptr_t thinFlag = 1; > static const uintptr_t reservedFlag = 2; >- static const uintptr_t flags = 3; >+ 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; >+ }; >+ > void copyFrom(const StructureSet&); > > class OutOfLineList { >@@ -154,7 +201,7 @@ private: > > void deleteStructureListIfNecessary() > { >- if (!isThin()) >+ if (!isThin() && m_pointer != reservedValue) > OutOfLineList::destroy(structureList()); > } > >@@ -185,10 +232,22 @@ private: > { > 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; > }; >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h (working copy) >@@ -114,6 +114,7 @@ public: > bool executeEffects(unsigned indexInBlock); > bool executeEffects(unsigned clobberLimit, Node*); > >+ void dump(PrintStream& out) const; > void dump(PrintStream& out); > > template<typename T> >@@ -148,7 +149,13 @@ public: > private: > void clobberWorld(const CodeOrigin&, unsigned indexInBlock); > void clobberCapturedVars(const CodeOrigin&); >+ >+ template<typename Functor> >+ void forAllValues(unsigned indexInBlock, Functor&); >+ > void clobberStructures(unsigned indexInBlock); >+ void observeTransition(unsigned indexInBlock, Structure* from, Structure* to); >+ void observeTransitions(unsigned indexInBlock, const TransitionVector&); > > enum BooleanResult { > UnknownBooleanResult, >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (working copy) >@@ -62,11 +62,17 @@ AbstractInterpreter<AbstractStateType>:: > } > > // 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,18 @@ void AbstractInterpreter<AbstractStateTy > } > > 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; >+ >+ startCrashing(); >+ dataLog("Edge verification error: ", node, "->", edge, " was expected to have type ", SpeculationDump(typeFilterFor(edge.useKind())), " but has type ", SpeculationDump(forNode(edge).m_type), "\n"); >+ dataLog(" Full value: ", forNode(edge), "\n"); >+ dataLog("\n"); >+ dataLog("Graph at time of failure:\n"); >+ m_graph.dump(); >+ RELEASE_ASSERT_NOT_REACHED(); > } > > template<typename AbstractStateType> >@@ -1456,7 +1471,12 @@ bool AbstractInterpreter<AbstractStateTy > 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()]); >@@ -1466,9 +1486,14 @@ bool AbstractInterpreter<AbstractStateTy > 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(); >+ if (structure->transitionWatchpointSetIsStillValid()) >+ m_graph.watchpoints().addLazily(structure->transitionWatchpointSet()); >+ } > setConstant(node, status[0].specificValue()); >- else >+ } else > forNode(node).makeHeapTop(); > filter(node->child1(), status[0].structureSet()); > >@@ -1502,8 +1527,12 @@ bool AbstractInterpreter<AbstractStateTy > 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; > } >@@ -1511,34 +1540,16 @@ bool AbstractInterpreter<AbstractStateTy > 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); >+ if (!forNode(node->child1()).m_structure.isClear()) { >+ observeTransition( >+ clobberLimit, node->transition()->previous, node->transition()->next); >+ forNode(node->child1()).set(m_graph, node->transition()->next); > m_state.setHaveStructures(true); > } > break; >@@ -1616,13 +1627,39 @@ bool AbstractInterpreter<AbstractStateTy > } > 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); >+ >+ // 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()); > m_state.setHaveStructures(true); > break; > } >@@ -1651,7 +1688,11 @@ bool AbstractInterpreter<AbstractStateTy > 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]; >@@ -1677,6 +1718,7 @@ bool AbstractInterpreter<AbstractStateTy > > filter(node->child1(), set); > forNode(node).makeHeapTop(); >+ m_state.setHaveStructures(true); > break; > } > >@@ -1688,7 +1730,12 @@ bool AbstractInterpreter<AbstractStateTy > 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]; >@@ -1715,25 +1762,25 @@ bool AbstractInterpreter<AbstractStateTy > 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.add(variant.structure()); >- continue; >- } >- ASSERT(variant.kind() == PutByIdVariant::Transition); >- if (value.m_currentKnownStructure.contains(variant.oldStructure())) >+ 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()); >+ } > } > >- // 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); >+ m_state.setHaveStructures(true); >+ observeTransitions(clobberLimit, transitions); >+ forNode(node->child1()).set(m_graph, newSet); > break; > } > >@@ -1767,7 +1814,12 @@ bool AbstractInterpreter<AbstractStateTy > 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), >@@ -1781,7 +1833,10 @@ bool AbstractInterpreter<AbstractStateTy > m_state.setHaveStructures(true); > break; > } >- if (status[0].kind() == PutByIdVariant::Transition) { >+ if (status[0].kind() == PutByIdVariant::Transition >+ && structure->transitionWatchpointSetHasBeenInvalidated()) { >+ if (status[0].newStructure()->transitionWatchpointSetIsStillValid()) >+ m_graph.watchpoints().addLazily(status[0].newStructure()->transitionWatchpointSet()); > clobberStructures(clobberLimit); > forNode(node->child1()).set(m_graph, status[0].newStructure()); > m_state.setHaveStructures(true); >@@ -1855,6 +1910,7 @@ bool AbstractInterpreter<AbstractStateTy > > case InvalidationPoint: > node->setCanExit(true); >+ forAllValues(clobberLimit, AbstractValue::observeInvalidationPointFor); > break; > > case CheckWatchdogTimer: >@@ -1957,32 +2013,67 @@ void AbstractInterpreter<AbstractStateTy > } > > 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; > 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) >+{ >+ if (!m_state.haveStructures()) >+ return; >+ forAllValues(clobberLimit, AbstractValue::clobberStructuresFor); >+ m_state.setDidClobber(true); >+} >+ >+template<typename AbstractStateType> >+void AbstractInterpreter<AbstractStateType>::observeTransition( >+ unsigned clobberLimit, Structure* from, Structure* to) >+{ >+ if (!m_state.haveStructures()) >+ return; >+ AbstractValue::TransitionObserver transitionObserver(from, to); >+ forAllValues(clobberLimit, transitionObserver); >+ m_state.setDidClobber(true); >+} >+ >+template<typename AbstractStateType> >+void AbstractInterpreter<AbstractStateType>::observeTransitions( >+ unsigned clobberLimit, const TransitionVector& vector) >+{ >+ if (!m_state.haveStructures()) >+ return; >+ AbstractValue::TransitionsObserver transitionsObserver(vector); >+ forAllValues(clobberLimit, transitionsObserver); > m_state.setDidClobber(true); > } > > 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(" "); >Index: Source/JavaScriptCore/dfg/DFGAbstractValue.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractValue.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGAbstractValue.cpp (working copy) >@@ -33,16 +33,30 @@ > > 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); >+ if (structure->transitionWatchpointSetIsStillValid()) >+ graph.watchpoints().addLazily(structure->transitionWatchpointSet()); >+ m_structure = structure; > m_arrayModes = asArrayModes(structure->indexingType()); > } else { >- m_currentKnownStructure.clear(); >- m_futurePossibleStructure.clear(); >+ m_structure.clear(); > m_arrayModes = 0; > } > >@@ -50,19 +64,25 @@ void AbstractValue::setMostSpecific(Grap > m_value = value; > > checkConsistency(); >+ assertIsWatched(graph); > } > > void AbstractValue::set(Graph& graph, JSValue value) > { > if (!!value && value.isCell()) { >- m_currentKnownStructure.makeTop(); >+ m_structure.makeTop(); > Structure* structure = value.asCell()->structure(); >- setFuturePossibleStructure(graph, structure); >+ if (structure->transitionWatchpointSetIsStillValid()) { >+ // 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. >+ // https://bugs.webkit.org/show_bug.cgi?id=133426 >+ graph.watchpoints().addLazily(structure->transitionWatchpointSet()); >+ m_structure = structure; >+ } > m_arrayModes = asArrayModes(structure->indexingType()); > clobberArrayModes(); > } else { >- m_currentKnownStructure.clear(); >- m_futurePossibleStructure.clear(); >+ m_structure.clear(); > m_arrayModes = 0; > } > >@@ -70,17 +90,29 @@ void AbstractValue::set(Graph& graph, JS > 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) >@@ -129,21 +161,18 @@ FiltrationResult AbstractValue::filter(G > > 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) >@@ -169,8 +198,7 @@ FiltrationResult AbstractValue::filter(S > // 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(); >@@ -184,15 +212,6 @@ FiltrationResult AbstractValue::filterBy > 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 >@@ -238,8 +257,7 @@ bool AbstractValue::shouldBeClear() cons > return true; > > if (!(m_type & ~SpecCell) >- && (!m_arrayModes >- || m_currentKnownStructure.isClear())) >+ && (!m_arrayModes || m_structure.isClear())) > return true; > > return false; >@@ -263,12 +281,18 @@ FiltrationResult AbstractValue::normaliz > 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); > } > >@@ -289,6 +313,11 @@ void AbstractValue::checkConsistency() c > // 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 >@@ -302,8 +331,7 @@ void AbstractValue::dumpInContext(PrintS > if (m_type & SpecCell) { > out.print( > ", ", ArrayModesDump(m_arrayModes), ", ", >- inContext(m_currentKnownStructure, context), ", ", >- inContext(m_futurePossibleStructure, context)); >+ inContext(m_structure, context)); > } > if (!!m_value) > out.print(", ", inContext(m_value, context)); >Index: Source/JavaScriptCore/dfg/DFGAbstractValue.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractValue.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGAbstractValue.h (working copy) >@@ -53,8 +53,7 @@ struct AbstractValue { > { > m_type = SpecNone; > m_arrayModes = 0; >- m_currentKnownStructure.clear(); >- m_futurePossibleStructure.clear(); >+ m_structure.clear(); > m_value = JSValue(); > checkConsistency(); > } >@@ -75,15 +74,74 @@ struct AbstractValue { > void clobberStructures() > { > if (m_type & SpecCell) { >- m_currentKnownStructure.makeTop(); >+ m_structure.clobber(); > clobberArrayModes(); > } else { >- ASSERT(m_currentKnownStructure.isClear()); >+ ASSERT(m_structure.isClear()); > ASSERT(!m_arrayModes); > } > checkConsistency(); > } >+ >+ static void clobberStructuresFor(AbstractValue& value) >+ { >+ value.clobberStructures(); >+ } >+ >+ void observeInvalidationPoint() >+ { >+ m_structure.observeInvalidationPoint(); >+ checkConsistency(); >+ } >+ >+ static void observeInvalidationPointFor(AbstractValue& value) >+ { >+ value.observeInvalidationPoint(); >+ } >+ >+ void observeTransition(Structure* from, Structure* to) >+ { >+ if (m_type & SpecCell) { >+ m_structure.observeTransition(from, to); >+ observeIndexingTypeTransition(from->indexingType(), to->indexingType()); >+ } >+ checkConsistency(); >+ } >+ >+ void observeTransitions(const TransitionVector& vector); >+ >+ class TransitionObserver { >+ public: >+ TransitionObserver(Structure* from, Structure* to) >+ : m_from(from) >+ , m_to(to) >+ { >+ } >+ >+ void operator()(AbstractValue& value) >+ { >+ value.observeTransition(m_from, m_to); >+ } >+ private: >+ Structure* m_from; >+ Structure* m_to; >+ }; >+ >+ class TransitionsObserver { >+ public: >+ TransitionsObserver(const TransitionVector& vector) >+ : m_vector(vector) >+ { >+ } > >+ void operator()(AbstractValue& value) >+ { >+ value.observeTransitions(m_vector); >+ } >+ private: >+ const TransitionVector& m_vector; >+ }; >+ > void clobberValue() > { > m_value = JSValue(); >@@ -91,7 +149,10 @@ struct AbstractValue { > > bool isHeapTop() const > { >- return (m_type | SpecHeapTop) == m_type && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop(); >+ return (m_type | SpecHeapTop) == m_type >+ && m_structure.isTop() >+ && m_arrayModes == ALL_ARRAY_MODES >+ && !m_value; > } > > bool valueIsTop() const >@@ -114,16 +175,15 @@ struct AbstractValue { > void setMostSpecific(Graph&, JSValue); > void set(Graph&, JSValue); > 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 +198,7 @@ struct AbstractValue { > { > return m_type == other.m_type > && m_arrayModes == other.m_arrayModes >- && m_currentKnownStructure == other.m_currentKnownStructure >- && m_futurePossibleStructure == other.m_futurePossibleStructure >+ && m_structure == other.m_structure > && m_value == other.m_value; > } > bool operator!=(const AbstractValue& other) const >@@ -162,8 +221,7 @@ struct AbstractValue { > } else { > result |= mergeSpeculation(m_type, other.m_type); > result |= mergeArrayModes(m_arrayModes, other.m_arrayModes); >- result |= m_currentKnownStructure.addAll(other.m_currentKnownStructure); >- result |= m_futurePossibleStructure.addAll(other.m_futurePossibleStructure); >+ result |= m_structure.merge(other.m_structure); > if (m_value != other.m_value) { > result |= !!m_value; > m_value = JSValue(); >@@ -179,8 +237,7 @@ struct AbstractValue { > mergeSpeculation(m_type, type); > > if (type & SpecCell) { >- m_currentKnownStructure.makeTop(); >- m_futurePossibleStructure.makeTop(); >+ m_structure.makeTop(); > m_arrayModes = ALL_ARRAY_MODES; > } > m_value = JSValue(); >@@ -225,75 +282,30 @@ struct AbstractValue { > if (!!value && value.isCell()) { > ASSERT(m_type & SpecCell); > Structure* structure = value.asCell()->structure(); >- return m_currentKnownStructure.contains(structure) >- && m_futurePossibleStructure.contains(structure) >+ return m_structure.contains(structure) > && (m_arrayModes & asArrayModes(structure->indexingType())); > } > > return true; > } > >- Structure* bestProvenStructure() const >- { >- if (m_currentKnownStructure.hasSingleton()) >- return m_currentKnownStructure.singleton(); >- if (m_futurePossibleStructure.hasSingleton()) >- return m_futurePossibleStructure.singleton(); >- return 0; >- } >- > bool hasClobberableState() const > { >- return m_currentKnownStructure.isNeitherClearNorTop() >+ return m_structure.isNeitherClearNorTop() > || !arrayModesAreClearOrTop(m_arrayModes); > } > > #if ASSERT_DISABLED > void checkConsistency() const { } >+ void assertIsWatched(Graph&) const { } > #else > void checkConsistency() const; >+ void assertIsWatched(Graph&) const; > #endif > > void dumpInContext(PrintStream&, DumpContext*) const; > void dump(PrintStream&) const; > >- // A great way to think about the difference between m_currentKnownStructure and >- // m_futurePossibleStructure is to consider these four examples: >- // >- // 1) x = foo(); >- // >- // In this case x's m_currentKnownStructure and m_futurePossibleStructure will >- // both be TOP, since we don't know anything about x for sure, yet. >- // >- // 2) x = foo(); >- // y = x.f; >- // >- // Where x will later have a new property added to it, 'g'. Because of the >- // known but not-yet-executed property addition, x's current structure will >- // not be watchpointable; hence we have no way of statically bounding the set >- // of possible structures that x may have if a clobbering event happens. So, >- // x's m_currentKnownStructure will be whatever structure we check to get >- // property 'f', and m_futurePossibleStructure will be TOP. >- // >- // 3) x = foo(); >- // y = x.f; >- // >- // Where x has a terminal structure that is still watchpointable. In this case, >- // x's m_currentKnownStructure and m_futurePossibleStructure will both be >- // whatever structure we checked for when getting 'f'. >- // >- // 4) x = foo(); >- // y = x.f; >- // bar(); >- // >- // Where x has a terminal structure that is still watchpointable. In this >- // case, m_currentKnownStructure will be TOP because bar() may potentially >- // change x's structure and we have no way of proving otherwise, but >- // x's m_futurePossibleStructure will be whatever structure we had checked >- // when getting property 'f'. >- >- // NB. All fields in this struct must have trivial destructors. >- > // This is a proven constraint on the structures that this value can have right > // now. The structure of the current value must belong to this set. The set may > // be TOP, indicating that it is the set of all possible structures, in which >@@ -301,29 +313,12 @@ struct AbstractValue { > // in which case this value cannot be a cell. This is all subject to change > // anytime a new value is assigned to this one, anytime there is a control flow > // merge, or most crucially, anytime a side-effect or structure check happens. >- // In case of a side-effect, we typically must assume that any value may have >- // had its structure changed, hence contravening our proof. We make the proof >- // valid again by switching this to TOP (i.e. claiming that we have proved that >- // this value may have any structure). Of note is that the proof represented by >- // this field is not subject to structure transition watchpoints - even if one >- // fires, we can be sure that this proof is still valid. >- StructureAbstractValue m_currentKnownStructure; >- >- // This is a proven constraint on the structures that this value can have now >- // or any time in the future subject to the structure transition watchpoints of >- // all members of this set not having fired. This set is impervious to side- >- // effects; even if one happens the side-effect can only cause the value to >- // change to at worst another structure that is also a member of this set. But, >- // the theorem being proved by this field is predicated upon there not being >- // any new structure transitions introduced into any members of this set. In >- // cases where there is no way for us to guard this happening, the set must be >- // TOP. But in cases where we can guard new structure transitions (all members >- // of the set have still-valid structure transition watchpoints) then this set >- // will be finite. Anytime that we make use of the finite nature of this set, >- // we must first issue a structure transition watchpoint, which will effectively >- // result in m_currentKnownStructure being filtered according to >- // m_futurePossibleStructure. >- StructureAbstractValue m_futurePossibleStructure; >+ // In case of a side-effect, we must assume that any value with a structure that >+ // isn't being watched may have had its structure changed, hence contravening >+ // our proof. In such a case we make the proof valid again by switching this to >+ // TOP (i.e. claiming that we have proved that this value may have any >+ // structure). >+ StructureAbstractValue m_structure; > > // This is a proven constraint on the possible types that this value can have > // now or any time in the future, unless it is reassigned. This field is >@@ -332,11 +327,11 @@ struct AbstractValue { > // between this field, and the structure fields above, is as follows. The > // fields above constraint the structures that a cell may have, but they say > // nothing about whether or not the value is known to be a cell. More formally, >- // the m_currentKnownStructure is itself an abstract value that consists of the >+ // the m_structure is itself an abstract value that consists of the > // union of the set of all non-cell values and the set of cell values that have > // the given structure. This abstract value is then the intersection of the >- // m_currentKnownStructure and the set of values whose type is m_type. So, for >- // example if m_type is SpecFinal|SpecInt32 and m_currentKnownStructure is >+ // m_structure and the set of values whose type is m_type. So, for >+ // example if m_type is SpecFinal|SpecInt32 and m_structure is > // [0x12345] then this abstract value corresponds to the set of all integers > // unified with the set of all objects with structure 0x12345. > SpeculatedType m_type; >@@ -364,6 +359,12 @@ private: > m_arrayModes = ALL_ARRAY_MODES; > } > >+ void observeIndexingTypeTransition(IndexingType from, IndexingType to) >+ { >+ if (m_arrayModes & asArrayModes(from)) >+ m_arrayModes |= asArrayModes(to); >+ } >+ > bool validateType(JSValue value) const > { > if (isHeapTop()) >@@ -391,19 +392,17 @@ private: > { > m_type |= top; > m_arrayModes = ALL_ARRAY_MODES; >- m_currentKnownStructure.makeTop(); >- m_futurePossibleStructure.makeTop(); >+ m_structure.makeTop(); > m_value = JSValue(); > checkConsistency(); > } > >- void setFuturePossibleStructure(Graph&, Structure* structure); >- > void filterValueByType(); > void filterArrayModesByType(); > > bool shouldBeClear() const; > FiltrationResult normalizeClarity(); >+ FiltrationResult normalizeClarity(Graph&); > }; > > } } // namespace JSC::DFG >Index: Source/JavaScriptCore/dfg/DFGAllocator.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAllocator.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGAllocator.h (working copy) >@@ -50,7 +50,7 @@ public: > void* allocate(); // Use placement new to allocate, and avoid using this method. > void free(T*); // Call this method to delete; never use 'delete' directly. > >- void freeAll(); // Only call this if T has a trivial destructor. >+ void freeAll(); // Only call this if you've either freed everything or if T has a trivial destructor. > void reset(); // Like freeAll(), but also returns all memory to the OS. > > unsigned indexOf(const T*); >Index: Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp (working copy) >@@ -325,7 +325,6 @@ public: > break; > > case CheckStructure: >- case StructureTransitionWatchpoint: > case CheckArray: > // We don't care about these because if we get uses of the relevant > // variable then we can safely get rid of these, too. This of course >@@ -441,7 +440,6 @@ public: > } > > case CheckStructure: >- case StructureTransitionWatchpoint: > case CheckArray: { > // We can just get rid of this node, if it references a phantom argument. > if (!isOKToOptimize(node->child1().node())) >Index: Source/JavaScriptCore/dfg/DFGArrayMode.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGArrayMode.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGArrayMode.cpp (working copy) >@@ -289,25 +289,48 @@ Structure* ArrayMode::originalArrayStruc > bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value, IndexingType shape) const > { > switch (arrayClass()) { >- case Array::OriginalArray: >- return value.m_currentKnownStructure.hasSingleton() >- && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape >- && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray) >- && graph.globalObjectFor(node->origin.semantic)->isOriginalArrayStructure(value.m_currentKnownStructure.singleton()); >+ case Array::OriginalArray: { >+ if (value.m_structure.isTop()) >+ return false; >+ for (unsigned i = value.m_structure.size(); i--;) { >+ Structure* structure = value.m_structure[i]; >+ if ((structure->indexingType() & IndexingShapeMask) != shape) >+ return false; >+ if (!(structure->indexingType() & IsArray)) >+ return false; >+ if (!graph.globalObjectFor(node->origin.semantic)->isOriginalArrayStructure(structure)) >+ return false; >+ } >+ return true; >+ } > >- case Array::Array: >+ case Array::Array: { > if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape | IsArray))) > return true; >- return value.m_currentKnownStructure.hasSingleton() >- && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape >- && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray); >+ if (value.m_structure.isTop()) >+ return false; >+ for (unsigned i = value.m_structure.size(); i--;) { >+ Structure* structure = value.m_structure[i]; >+ if ((structure->indexingType() & IndexingShapeMask) != shape) >+ return false; >+ if (!(structure->indexingType() & IsArray)) >+ return false; >+ } >+ return true; >+ } > >- default: >+ default: { > if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape) | asArrayModes(shape | IsArray))) > return true; >- return value.m_currentKnownStructure.hasSingleton() >- && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape; >- } >+ if (value.m_structure.isTop()) >+ return false; >+ for (unsigned i = value.m_structure.size(); i--;) { >+ Structure* structure = value.m_structure[i]; >+ if ((structure->indexingType() & IndexingShapeMask) != shape) >+ return false; >+ } >+ return true; >+ } } > } > > bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value) const >@@ -336,23 +359,38 @@ bool ArrayMode::alreadyChecked(Graph& gr > > case Array::SlowPutArrayStorage: > switch (arrayClass()) { >- case Array::OriginalArray: >+ case Array::OriginalArray: { > CRASH(); > return false; >+ } > >- case Array::Array: >+ case Array::Array: { > if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage))) > return true; >- return value.m_currentKnownStructure.hasSingleton() >- && hasAnyArrayStorage(value.m_currentKnownStructure.singleton()->indexingType()) >- && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray); >+ if (value.m_structure.isTop()) >+ return false; >+ for (unsigned i = value.m_structure.size(); i--;) { >+ Structure* structure = value.m_structure[i]; >+ if (!hasAnyArrayStorage(structure->indexingType())) >+ return false; >+ if (!(structure->indexingType() & IsArray)) >+ return false; >+ } >+ return true; >+ } > >- default: >+ default: { > if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage))) > return true; >- return value.m_currentKnownStructure.hasSingleton() >- && hasAnyArrayStorage(value.m_currentKnownStructure.singleton()->indexingType()); >- } >+ if (value.m_structure.isTop()) >+ return false; >+ for (unsigned i = value.m_structure.size(); i--;) { >+ Structure* structure = value.m_structure[i]; >+ if (!hasAnyArrayStorage(structure->indexingType())) >+ return false; >+ } >+ return true; >+ } } > > case Array::Arguments: > return speculationChecked(value.m_type, SpecArguments); >Index: Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (working copy) >@@ -2109,8 +2109,8 @@ void ByteCodeParser::handlePutById( > ASSERT(variant.oldStructure()->transitionWatchpointSetHasBeenInvalidated()); > > Node* propertyStorage; >- StructureTransitionData* transitionData = m_graph.addStructureTransitionData( >- StructureTransitionData(variant.oldStructure(), variant.newStructure())); >+ Transition* transition = m_graph.m_transitions.add( >+ variant.oldStructure(), variant.newStructure()); > > if (variant.oldStructure()->outOfLineCapacity() > != variant.newStructure()->outOfLineCapacity()) { >@@ -2121,10 +2121,10 @@ void ByteCodeParser::handlePutById( > > if (!variant.oldStructure()->outOfLineCapacity()) { > propertyStorage = addToGraph( >- AllocatePropertyStorage, OpInfo(transitionData), base); >+ AllocatePropertyStorage, OpInfo(transition), base); > } else { > propertyStorage = addToGraph( >- ReallocatePropertyStorage, OpInfo(transitionData), >+ ReallocatePropertyStorage, OpInfo(transition), > base, addToGraph(GetButterfly, base)); > } > } else { >@@ -2134,7 +2134,7 @@ void ByteCodeParser::handlePutById( > propertyStorage = addToGraph(GetButterfly, base); > } > >- addToGraph(PutStructure, OpInfo(transitionData), base); >+ addToGraph(PutStructure, OpInfo(transition), base); > > addToGraph( > PutByOffset, >Index: Source/JavaScriptCore/dfg/DFGCFAPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCFAPhase.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGCFAPhase.cpp (working copy) >@@ -102,7 +102,7 @@ private: > if (!safeToExecute(m_state, m_graph, node)) > dataLog("(UNSAFE) "); > >- m_interpreter.dump(WTF::dataFile()); >+ dataLog(m_state.variables(), " ", m_interpreter); > > if (m_state.haveStructures()) > dataLog(" (Have Structures)"); >Index: Source/JavaScriptCore/dfg/DFGCSEPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCSEPhase.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGCSEPhase.cpp (working copy) >@@ -460,17 +460,11 @@ private: > return true; > break; > >- case StructureTransitionWatchpoint: >- if (node->child1() == child1 >- && structureSet.contains(node->structure())) >- return true; >- break; >- > case PutStructure: > if (node->child1() == child1 >- && structureSet.contains(node->structureTransitionData().newStructure)) >+ && structureSet.contains(node->transition()->next)) > return true; >- if (structureSet.contains(node->structureTransitionData().previousStructure)) >+ if (structureSet.contains(node->transition()->previous)) > return false; > break; > >@@ -524,7 +518,7 @@ private: > break; > > case PutStructure: >- ASSERT(node->structureTransitionData().previousStructure != structure); >+ ASSERT(node->transition()->previous != structure); > break; > > case PutByOffset: >@@ -547,11 +541,6 @@ private: > } > return false; > >- case StructureTransitionWatchpoint: >- if (node->structure() == structure && node->child1() == child1) >- return true; >- break; >- > case Arrayify: > case ArrayifyToStructure: > // We could check if the arrayification could affect our structures. >@@ -1387,13 +1376,6 @@ private: > eliminate(); > break; > >- case StructureTransitionWatchpoint: >- if (cseMode == StoreElimination) >- break; >- if (structureTransitionWatchpointElimination(node->structure(), node->child1().node())) >- eliminate(); >- break; >- > case PutStructure: > if (cseMode == NormalCSE) > break; >Index: Source/JavaScriptCore/dfg/DFGClobberize.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGClobberize.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGClobberize.h (working copy) >@@ -418,7 +418,6 @@ void clobberize(Graph& graph, Node* node > } > > case CheckStructure: >- case StructureTransitionWatchpoint: > case InstanceOf: > read(JSCell_structureID); > return; >Index: Source/JavaScriptCore/dfg/DFGCommon.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCommon.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGCommon.cpp (working copy) >@@ -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 { >Index: Source/JavaScriptCore/dfg/DFGCommon.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCommon.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGCommon.h (working copy) >@@ -211,6 +211,8 @@ bool checkAndSet(T& left, U right) > // when you're forcing a crash with diagnostics. > void startCrashing(); > >+JS_EXPORT_PRIVATE bool isCrashing(); >+ > } } // namespace JSC::DFG > > namespace WTF { >Index: Source/JavaScriptCore/dfg/DFGCommonData.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCommonData.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGCommonData.cpp (working copy) >@@ -41,8 +41,8 @@ void CommonData::notifyCompilingStructur > plan.transitions.addLazily( > codeBlock, > node->origin.semantic.codeOriginOwner(), >- node->structureTransitionData().previousStructure, >- node->structureTransitionData().newStructure); >+ node->transition()->previous, >+ node->transition()->next); > } > > unsigned CommonData::addCodeOrigin(CodeOrigin codeOrigin) >Index: Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (working copy) >@@ -97,27 +97,12 @@ private: > set = node->structure(); > else > set = node->structureSet(); >- if (value.m_currentKnownStructure.isSubsetOf(set)) { >+ if (value.m_structure.isSubsetOf(set)) { > m_interpreter.execute(indexInBlock); // Catch the fact that we may filter on cell. > node->convertToPhantom(); > eliminated = true; > break; > } >- StructureAbstractValue& structureValue = value.m_futurePossibleStructure; >- if (structureValue.isSubsetOf(set) >- && structureValue.hasSingleton()) { >- Structure* structure = structureValue.singleton(); >- m_interpreter.execute(indexInBlock); // Catch the fact that we may filter on cell. >- AdjacencyList children = node->children; >- children.removeEdge(0); >- if (!!children.child1()) >- m_insertionSet.insertNode(indexInBlock, SpecNone, Phantom, node->origin, children); >- node->children.setChild2(Edge()); >- node->children.setChild3(Edge()); >- node->convertToStructureTransitionWatchpoint(structure); >- eliminated = true; >- break; >- } > break; > } > >@@ -156,7 +141,7 @@ private: > Node* child = childEdge.node(); > MultiGetByOffsetData& data = node->multiGetByOffsetData(); > >- Structure* structure = m_state.forNode(child).bestProvenStructure(); >+ Structure* structure = m_state.forNode(child).m_structure.onlyStructure(); > if (!structure) > break; > >@@ -180,7 +165,7 @@ private: > Node* child = childEdge.node(); > MultiPutByOffsetData& data = node->multiPutByOffsetData(); > >- Structure* structure = m_state.forNode(child).bestProvenStructure(); >+ Structure* structure = m_state.forNode(child).m_structure.onlyStructure(); > if (!structure) > break; > >@@ -205,7 +190,7 @@ private: > if (childEdge.useKind() != CellUse) > break; > >- Structure* structure = m_state.forNode(child).bestProvenStructure(); >+ Structure* structure = m_state.forNode(child).m_structure.onlyStructure(); > if (!structure) > break; > >@@ -232,7 +217,7 @@ private: > > ASSERT(childEdge.useKind() == CellUse); > >- Structure* structure = m_state.forNode(child).bestProvenStructure(); >+ Structure* structure = m_state.forNode(child).m_structure.onlyStructure(); > if (!structure) > break; > >@@ -329,7 +314,6 @@ private: > Edge childEdge = node->child1(); > Node* child = childEdge.node(); > >- bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton(); > bool needsCellCheck = m_state.forNode(child).m_type & ~SpecCell; > > ASSERT(!variant.chain()); >@@ -340,11 +324,7 @@ private: > // do any eliminations. > m_interpreter.execute(indexInBlock); > >- if (needsWatchpoint) { >- m_insertionSet.insertNode( >- indexInBlock, SpecNone, StructureTransitionWatchpoint, origin, >- OpInfo(structure), childEdge); >- } else if (needsCellCheck) { >+ if (needsCellCheck) { > m_insertionSet.insertNode( > indexInBlock, SpecNone, Phantom, origin, childEdge); > } >@@ -381,7 +361,6 @@ private: > > ASSERT(variant.oldStructure() == structure); > >- bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton(); > bool needsCellCheck = m_state.forNode(child).m_type & ~SpecCell; > > // Now before we do anything else, push the CFA forward over the PutById >@@ -389,21 +368,16 @@ private: > // do any eliminations. > m_interpreter.execute(indexInBlock); > >- if (needsWatchpoint) { >- m_insertionSet.insertNode( >- indexInBlock, SpecNone, StructureTransitionWatchpoint, origin, >- OpInfo(structure), childEdge); >- } else if (needsCellCheck) { >+ if (needsCellCheck) { > m_insertionSet.insertNode( > indexInBlock, SpecNone, Phantom, origin, childEdge); > } > > childEdge.setUseKind(KnownCellUse); > >- StructureTransitionData* transitionData = 0; >+ Transition* transition = 0; > if (variant.kind() == PutByIdVariant::Transition) { >- transitionData = m_graph.addStructureTransitionData( >- StructureTransitionData(structure, variant.newStructure())); >+ transition = m_graph.m_transitions.add(structure, variant.newStructure()); > > if (node->op() == PutById) { > if (!structure->storedPrototype().isNull()) { >@@ -439,7 +413,7 @@ private: > ASSERT(!isInlineOffset(variant.offset())); > Node* allocatePropertyStorage = m_insertionSet.insertNode( > indexInBlock, SpecNone, AllocatePropertyStorage, >- origin, OpInfo(transitionData), childEdge); >+ origin, OpInfo(transition), childEdge); > m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node->child1().node(), KnownCellUse)); > propertyStorage = Edge(allocatePropertyStorage); > } else { >@@ -449,7 +423,7 @@ private: > > Node* reallocatePropertyStorage = m_insertionSet.insertNode( > indexInBlock, SpecNone, ReallocatePropertyStorage, origin, >- OpInfo(transitionData), childEdge, >+ OpInfo(transition), childEdge, > Edge(m_insertionSet.insertNode( > indexInBlock, SpecNone, GetButterfly, origin, childEdge))); > m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node->child1().node(), KnownCellUse)); >@@ -457,7 +431,7 @@ private: > } > > if (variant.kind() == PutByIdVariant::Transition) { >- Node* putStructure = m_graph.addNode(SpecNone, PutStructure, origin, OpInfo(transitionData), childEdge); >+ Node* putStructure = m_graph.addNode(SpecNone, PutStructure, origin, OpInfo(transition), childEdge); > m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node->child1().node(), KnownCellUse)); > m_insertionSet.insert(indexInBlock, putStructure); > } >@@ -475,16 +449,14 @@ private: > > void addStructureTransitionCheck(NodeOrigin origin, unsigned indexInBlock, JSCell* cell) > { >- 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)); >+ if (cell->structure()->transitionWatchpointSetIsStillValid()) { >+ m_graph.watchpoints().addLazily(cell->structure()->transitionWatchpointSet()); > return; > } > >+ Node* weakConstant = m_insertionSet.insertNode( >+ indexInBlock, speculationFromValue(cell), WeakJSConstant, origin, OpInfo(cell)); >+ > m_insertionSet.insertNode( > indexInBlock, SpecNone, CheckStructure, origin, > OpInfo(m_graph.addStructureSet(cell->structure())), Edge(weakConstant, CellUse)); >Index: Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp (working copy) >@@ -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,16 +62,6 @@ void DesiredWatchpoints::addLazily(JSArr > m_bufferViews.addLazily(view); > } > >-void DesiredWatchpoints::addLazily(CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSet* set) >-{ >- m_sets.addLazily(codeOrigin, exitKind, set); >-} >- >-void DesiredWatchpoints::addLazily(CodeOrigin codeOrigin, ExitKind exitKind, InlineWatchpointSet& set) >-{ >- m_inlineSets.addLazily(codeOrigin, exitKind, &set); >-} >- > void DesiredWatchpoints::reallyAdd(CodeBlock* codeBlock, CommonData& commonData) > { > m_sets.reallyAdd(codeBlock, commonData); >Index: Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h (working copy) >@@ -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 @@ public: > m_sets.add(set); > } > >- void addLazily(CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSetType* set) >- { >- m_profiledWatchpoints.append( >- WatchpointForGenericWatchpointSet<WatchpointSetType>(codeOrigin, exitKind, set)); >- } >- > void reallyAdd(CodeBlock* codeBlock, CommonData& common) > { > RELEASE_ASSERT(!m_reallyAdded); >@@ -112,14 +87,6 @@ public: > Adaptor::add(codeBlock, *iter, &common.watchpoints.last()); > } > >- for (unsigned i = m_profiledWatchpoints.size(); i--;) { >- WatchpointForGenericWatchpointSet<WatchpointSetType> watchpoint = >- m_profiledWatchpoints[i]; >- common.profiledWatchpoints.append( >- ProfiledCodeBlockJettisoningWatchpoint(watchpoint.m_codeOrigin, watchpoint.m_exitKind, codeBlock)); >- Adaptor::add(codeBlock, watchpoint.m_set, &common.profiledWatchpoints.last()); >- } >- > m_reallyAdded = true; > } > >@@ -132,53 +99,16 @@ public: > return false; > } > >- for (unsigned i = m_profiledWatchpoints.size(); i--;) { >- if (Adaptor::hasBeenInvalidated(m_profiledWatchpoints[i].m_set)) >- return false; >- } >- >- return true; >- } >- >-#if ASSERT_DISABLED >- bool isStillValid(WatchpointSetType* set) >- { >- 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) >+ bool isWatched(WatchpointSetType* set) const > { >- 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,22 @@ public: > void addLazily(WatchpointSet*); > void addLazily(InlineWatchpointSet&); > void addLazily(JSArrayBufferView*); >- void addLazily(CodeOrigin, ExitKind, WatchpointSet*); >- void addLazily(CodeOrigin, ExitKind, InlineWatchpointSet&); > > void reallyAdd(CodeBlock*, CommonData&); > > bool areStillValid() const; > >- bool isStillValid(WatchpointSet* set) >- { >- return m_sets.isStillValid(set); >- } >- bool isStillValid(InlineWatchpointSet& set) >- { >- return m_inlineSets.isStillValid(&set); >- } >- bool isStillValid(JSArrayBufferView* view) >- { >- return m_bufferViews.isStillValid(view); >- } >- bool shouldAssumeMixedState(WatchpointSet* set) >- { >- return m_sets.shouldAssumeMixedState(set); >- } >- bool shouldAssumeMixedState(InlineWatchpointSet& set) >- { >- return m_inlineSets.shouldAssumeMixedState(&set); >- } >- bool shouldAssumeMixedState(JSArrayBufferView* view) >- { >- return m_bufferViews.shouldAssumeMixedState(view); >- } >- bool isValidOrMixed(WatchpointSet* set) >+ bool isWatched(WatchpointSet* set) > { >- return m_sets.isValidOrMixed(set); >+ return m_sets.isWatched(set); > } >- bool isValidOrMixed(InlineWatchpointSet& set) >+ bool isWatched(InlineWatchpointSet& set) > { >- return m_inlineSets.isValidOrMixed(&set); >+ return m_inlineSets.isWatched(&set); > } >- bool isValidOrMixed(JSArrayBufferView* view) >+ bool isWatched(JSArrayBufferView* view) > { >- return m_bufferViews.isValidOrMixed(view); >+ return m_bufferViews.isWatched(view); > } > > private: >Index: Source/JavaScriptCore/dfg/DFGDoesGC.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGDoesGC.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGDoesGC.cpp (working copy) >@@ -182,7 +182,6 @@ bool doesGC(Graph& graph, Node* node) > case PutByValDirect: > case PutByVal: > case PutByValAlias: >- case StructureTransitionWatchpoint: > case PutStructure: > case PhantomPutStructure: > case GetByOffset: >Index: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (working copy) >@@ -930,7 +930,6 @@ private: > > case CheckExecutable: > case CheckStructure: >- case StructureTransitionWatchpoint: > case CheckFunction: > case CheckHasInstance: > case CreateThis: >@@ -1351,7 +1350,7 @@ private: > > JSObject* stringPrototypeObject = asObject(stringObjectStructure->storedPrototype()); > Structure* stringPrototypeStructure = stringPrototypeObject->structure(); >- if (!m_graph.watchpoints().isStillValid(stringPrototypeStructure->transitionWatchpointSet())) >+ if (stringPrototypeStructure->transitionWatchpointSetHasBeenInvalidated()) > return false; > > if (stringPrototypeStructure->isDictionary()) >Index: Source/JavaScriptCore/dfg/DFGGraph.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGGraph.cpp (working copy) >@@ -77,6 +77,16 @@ Graph::Graph(VM& vm, Plan& plan, LongLiv > > Graph::~Graph() > { >+ for (BlockIndex blockIndex = numBlocks(); blockIndex--;) { >+ BasicBlock* block = this->block(blockIndex); >+ if (!block) >+ continue; >+ >+ for (unsigned phiIndex = block->phis.size(); phiIndex--;) >+ m_allocator.free(block->phis[phiIndex]); >+ for (unsigned nodeIndex = block->size(); nodeIndex--;) >+ m_allocator.free(block->at(nodeIndex)); >+ } > m_allocator.freeAll(); > } > >@@ -211,8 +221,8 @@ void Graph::dump(PrintStream& out, const > 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())) { >@@ -800,8 +810,9 @@ JSArrayBufferView* Graph::tryGetFoldable > 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 +857,6 @@ void Graph::visitChildren(SlotVisitor& v > visitor.appendUnbarrieredReadOnlyPointer(node->structureSet()[i]); > break; > >- case StructureTransitionWatchpoint: > case NewObject: > case ArrayifyToStructure: > case NewStringObject: >@@ -858,9 +868,34 @@ void Graph::visitChildren(SlotVisitor& v > 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 +905,20 @@ void Graph::visitChildren(SlotVisitor& v > } > } > >+void Graph::assertIsWatched(Structure* structure) >+{ >+ if (structure->transitionWatchpointSetHasBeenInvalidated()) >+ return; >+ if (watchpoints().isWatched(structure->transitionWatchpointSet())) >+ return; >+ >+ startCrashing(); >+ dataLog("Structure ", pointerDump(structure), " is watchable but isn't being watched.\n"); >+ dataLog("Graph at time of failure:\n"); >+ dump(); >+ CRASH(); >+} >+ > } } // namespace JSC::DFG > > #endif // ENABLE(DFG_JIT) >Index: Source/JavaScriptCore/dfg/DFGGraph.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGGraph.h (working copy) >@@ -169,8 +169,12 @@ public: > return constantRegister; > } > >+ void assertIsWatched(Structure* structure); >+ > void convertToConstant(Node* node, JSValue value) > { >+ if (value.isCell()) >+ assertIsWatched(value.asCell()->structure()); > if (value.isObject()) > node->convertToWeakConstant(value.asCell()); > else >@@ -390,12 +394,6 @@ public: > return &m_structureSet.last(); > } > >- StructureTransitionData* addStructureTransitionData(const StructureTransitionData& structureTransitionData) >- { >- m_structureTransitionData.append(structureTransitionData); >- return &m_structureTransitionData.last(); >- } >- > JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin) > { > return m_codeBlock->globalObjectFor(codeOrigin); >@@ -446,8 +444,7 @@ public: > > bool masqueradesAsUndefinedWatchpointIsStillValid(const CodeOrigin& codeOrigin) > { >- return m_plan.watchpoints.isStillValid( >- globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint()); >+ return globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid(); > } > > bool hasGlobalExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind) >@@ -823,7 +820,7 @@ public: > SegmentedVector<VariableAccessData, 16> m_variableAccessData; > SegmentedVector<ArgumentPosition, 8> m_argumentPositions; > SegmentedVector<StructureSet, 16> m_structureSet; >- SegmentedVector<StructureTransitionData, 8> m_structureTransitionData; >+ Bag<Transition> m_transitions; > SegmentedVector<NewArrayBufferData, 4> m_newArrayBufferData; > Bag<BranchData> m_branchData; > Bag<SwitchData> m_switchData; >Index: Source/JavaScriptCore/dfg/DFGNode.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNode.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGNode.h (working copy) >@@ -38,6 +38,7 @@ > #include "DFGNodeFlags.h" > #include "DFGNodeOrigin.h" > #include "DFGNodeType.h" >+#include "DFGTransition.h" > #include "DFGUseKind.h" > #include "DFGVariableAccessData.h" > #include "GetByIdVariant.h" >@@ -67,19 +68,6 @@ struct MultiPutByOffsetData { > bool reallocatesStorage() const; > }; > >-struct StructureTransitionData { >- Structure* previousStructure; >- Structure* newStructure; >- >- StructureTransitionData() { } >- >- StructureTransitionData(Structure* previousStructure, Structure* newStructure) >- : previousStructure(previousStructure) >- , newStructure(newStructure) >- { >- } >-}; >- > struct NewArrayBufferData { > unsigned startConstant; > unsigned numConstants; >@@ -485,21 +473,6 @@ struct Node { > children.reset(); > } > >- void convertToStructureTransitionWatchpoint(Structure* structure) >- { >- ASSERT(m_op == CheckStructure || m_op == ArrayifyToStructure); >- ASSERT(!child2()); >- ASSERT(!child3()); >- ASSERT(structure); >- m_opInfo = bitwise_cast<uintptr_t>(structure); >- m_op = StructureTransitionWatchpoint; >- } >- >- void convertToStructureTransitionWatchpoint() >- { >- convertToStructureTransitionWatchpoint(structureSet().onlyStructure()); >- } >- > void convertToGetByOffset(unsigned storageAccessDataIndex, Edge storage) > { > ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == MultiGetByOffset); >@@ -1091,7 +1064,7 @@ struct Node { > return reinterpret_cast<void*>(m_opInfo); > } > >- bool hasStructureTransitionData() >+ bool hasTransition() > { > switch (op()) { > case PutStructure: >@@ -1104,10 +1077,10 @@ struct Node { > } > } > >- StructureTransitionData& structureTransitionData() >+ Transition* transition() > { >- ASSERT(hasStructureTransitionData()); >- return *reinterpret_cast<StructureTransitionData*>(m_opInfo); >+ ASSERT(hasTransition()); >+ return reinterpret_cast<Transition*>(m_opInfo); > } > > bool hasStructureSet() >@@ -1129,7 +1102,6 @@ struct Node { > bool hasStructure() > { > switch (op()) { >- case StructureTransitionWatchpoint: > case ArrayifyToStructure: > case NewObject: > case NewStringObject: >Index: Source/JavaScriptCore/dfg/DFGNodeType.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNodeType.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGNodeType.h (working copy) >@@ -153,18 +153,6 @@ namespace JSC { namespace DFG { > macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \ > macro(CheckStructure, NodeMustGenerate) \ > macro(CheckExecutable, NodeMustGenerate) \ >- /* Transition watchpoints are a contract between the party setting the watchpoint */\ >- /* and the runtime system, where the party promises that the child object once had */\ >- /* the structure being watched, and the runtime system in turn promises that the */\ >- /* watchpoint will be turned into an OSR exit if any object with that structure */\ >- /* ever transitions to a different structure. Hence, the child object must have */\ >- /* previously had a CheckStructure executed on it or we're dealing with an object */\ >- /* constant (WeakJSConstant) and the object was known to have that structure at */\ >- /* compile-time. In the latter case this means that no structure checks have to be */\ >- /* performed for this object by JITted code. In the former case this means that*/\ >- /* the object's structure does not need to be rechecked due to side-effecting */\ >- /* (clobbering) operations. */\ >- macro(StructureTransitionWatchpoint, NodeMustGenerate) \ > macro(PutStructure, NodeMustGenerate) \ > macro(PhantomPutStructure, NodeMustGenerate | NodeDoesNotExit) \ > macro(AllocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \ >Index: Source/JavaScriptCore/dfg/DFGPlan.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPlan.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGPlan.cpp (working copy) >@@ -63,6 +63,7 @@ > #include "DFGUnificationPhase.h" > #include "DFGValidate.h" > #include "DFGVirtualRegisterAllocationPhase.h" >+#include "DFGWatchableStructureWatchingPhase.h" > #include "DFGWatchpointCollectionPhase.h" > #include "Debugger.h" > #include "OperandsInlines.h" >@@ -233,6 +234,7 @@ Plan::CompilationPath Plan::compileInThr > performBackwardsPropagation(dfg); > performPredictionPropagation(dfg); > performFixup(dfg); >+ performWatchableStructureWatching(dfg); > performInvalidationPointInjection(dfg); > performTypeCheckHoisting(dfg); > >Index: Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (working copy) >@@ -576,7 +576,6 @@ private: > case SetArgument: > case CheckStructure: > case CheckExecutable: >- case StructureTransitionWatchpoint: > case CheckFunction: > case PutStructure: > case TearOffActivation: >Index: Source/JavaScriptCore/dfg/DFGSafeToExecute.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSafeToExecute.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGSafeToExecute.h (working copy) >@@ -275,22 +275,26 @@ bool safeToExecute(AbstractStateType& st > return node->arrayMode().modeForPut().alreadyChecked( > graph, node, state.forNode(graph.varArgChild(node, 0))); > >- case StructureTransitionWatchpoint: >- return state.forNode(node->child1()).m_futurePossibleStructure.isSubsetOf( >- StructureSet(node->structure())); >- > case PutStructure: > case PhantomPutStructure: > case AllocatePropertyStorage: > case ReallocatePropertyStorage: >- return state.forNode(node->child1()).m_currentKnownStructure.isSubsetOf( >- StructureSet(node->structureTransitionData().previousStructure)); >+ return state.forNode(node->child1()).m_structure.isSubsetOf( >+ StructureSet(node->transition()->previous)); > > case GetByOffset: > case GetGetterSetterByOffset: >- case PutByOffset: >- return state.forNode(node->child1()).m_currentKnownStructure.isValidOffset( >- graph.m_storageAccessData[node->storageAccessDataIndex()].offset); >+ case PutByOffset: { >+ StructureAbstractValue& value = state.forNode(node->child1()).m_structure; >+ if (value.isTop()) >+ return false; >+ PropertyOffset offset = graph.m_storageAccessData[node->storageAccessDataIndex()].offset; >+ for (unsigned i = value.size(); i--;) { >+ if (!value[i]->isValidOffset(offset)) >+ return false; >+ } >+ return true; >+ } > > case LastNodeType: > RELEASE_ASSERT_NOT_REACHED(); >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (working copy) >@@ -3697,29 +3697,6 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >- case StructureTransitionWatchpoint: { >- // There is a fascinating question here of what to do about array profiling. >- // We *could* try to tell the OSR exit about where the base of the access is. >- // The DFG will have kept it alive, though it may not be in a register, and >- // we shouldn't really load it since that could be a waste. For now though, >- // we'll just rely on the fact that when a watchpoint fires then that's >- // quite a hint already. >- >- m_jit.addWeakReference(node->structure()); >- >-#if !ASSERT_DISABLED >- SpeculateCellOperand op1(this, node->child1()); >- JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureIDOffset()), TrustedImmPtr(node->structure())); >- m_jit.breakpoint(); >- isOK.link(&m_jit); >-#else >- speculateCell(node->child1()); >-#endif >- >- noResult(node); >- break; >- } >- > case PhantomPutStructure: { > ASSERT(isKnownCell(node->child1().node())); > m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node); >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (working copy) >@@ -3767,32 +3767,6 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >- case StructureTransitionWatchpoint: { >- // There is a fascinating question here of what to do about array profiling. >- // We *could* try to tell the OSR exit about where the base of the access is. >- // The DFG will have kept it alive, though it may not be in a register, and >- // we shouldn't really load it since that could be a waste. For now though, >- // we'll just rely on the fact that when a watchpoint fires then that's >- // quite a hint already. >- >- m_jit.addWeakReference(node->structure()); >- >-#if !ASSERT_DISABLED >- SpeculateCellOperand op1(this, node->child1()); >- JITCompiler::Jump isOK = m_jit.branchStructurePtr( >- JITCompiler::Equal, >- JITCompiler::Address(op1.gpr(), JSCell::structureIDOffset()), >- node->structure()); >- m_jit.breakpoint(); >- 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); >@@ -3801,8 +3775,8 @@ void SpeculativeJIT::compile(Node* node) > } > > case PutStructure: { >- Structure* oldStructure = node->structureTransitionData().previousStructure; >- Structure* newStructure = node->structureTransitionData().newStructure; >+ Structure* oldStructure = node->transition()->previous; >+ Structure* newStructure = node->transition()->next; > > m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node); > >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (working copy) >@@ -4298,7 +4298,7 @@ bool SpeculativeJIT::compileRegExpExec(N > > void SpeculativeJIT::compileAllocatePropertyStorage(Node* node) > { >- if (node->structureTransitionData().previousStructure->couldHaveIndexingHeader()) { >+ if (node->transition()->previous->couldHaveIndexingHeader()) { > SpeculateCellOperand base(this, node->child1()); > > GPRReg baseGPR = base.gpr(); >@@ -4318,8 +4318,8 @@ void SpeculativeJIT::compileAllocateProp > 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( >@@ -4337,11 +4337,11 @@ void SpeculativeJIT::compileAllocateProp > > void SpeculativeJIT::compileReallocatePropertyStorage(Node* node) > { >- size_t oldSize = node->structureTransitionData().previousStructure->outOfLineCapacity() * sizeof(JSValue); >+ size_t oldSize = node->transition()->previous->outOfLineCapacity() * sizeof(JSValue); > size_t newSize = oldSize * outOfLineGrowthFactor; >- ASSERT(newSize == node->structureTransitionData().newStructure->outOfLineCapacity() * sizeof(JSValue)); >+ ASSERT(newSize == node->transition()->next->outOfLineCapacity() * sizeof(JSValue)); > >- if (node->structureTransitionData().previousStructure->couldHaveIndexingHeader()) { >+ if (node->transition()->previous->couldHaveIndexingHeader()) { > SpeculateCellOperand base(this, node->child1()); > > GPRReg baseGPR = base.gpr(); >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (working copy) >@@ -3115,7 +3115,7 @@ void SpeculativeJIT::speculateStringObje > Structure* stringObjectStructure = > m_jit.globalObjectFor(m_currentNode->origin.semantic)->stringObjectStructure(); > >- if (!m_state.forNode(edge).m_currentKnownStructure.isSubsetOf(StructureSet(stringObjectStructure))) { >+ if (!m_state.forNode(edge).m_structure.isSubsetOf(StructureSet(stringObjectStructure))) { > speculationCheck( > NotStringObject, JSValueRegs(), 0, > m_jit.branchStructurePtr( >Index: Source/JavaScriptCore/dfg/DFGStructureAbstractValue.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGStructureAbstractValue.cpp (revision 0) >+++ Source/JavaScriptCore/dfg/DFGStructureAbstractValue.cpp (working copy) >@@ -0,0 +1,400 @@ >+/* >+ * 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 { >+ >+StructureAbstractValue::StructureAbstractValue(const StructureAbstractValue& other) >+ : m_set(other.m_set) >+{ >+ setClobbered(other.isClobbered()); >+} >+ >+StructureAbstractValue& StructureAbstractValue::operator=(const StructureAbstractValue& other) >+{ >+ m_set = other.m_set; >+ setClobbered(other.isClobbered()); >+ return *this; >+} >+ >+void StructureAbstractValue::makeTop() >+{ >+ m_set.deleteStructureListIfNecessary(); >+ m_set.m_pointer = topValue; >+} >+ >+void StructureAbstractValue::assertIsWatched(Graph& graph) const >+{ >+ if (isTop()) >+ return; >+ >+ for (unsigned i = size(); i--;) >+ graph.assertIsWatched(at(i)); >+} >+ >+void 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()->transitionWatchpointSetHasBeenInvalidated()) >+ makeTopWhenThin(); >+ return; >+ } >+ >+ StructureSet::OutOfLineList* list = m_set.structureList(); >+ for (unsigned i = list->m_length; i--;) { >+ if (list->list()[i]->transitionWatchpointSetHasBeenInvalidated()) { >+ makeTop(); >+ return; >+ } >+ } >+} >+ >+void StructureAbstractValue::observeTransition(Structure* from, Structure* to) >+{ >+ if (isTop()) >+ return; >+ >+ if (!m_set.contains(from)) >+ return; >+ >+ if (from->transitionWatchpointSetIsStillValid()) { >+ setClobbered(true); >+ return; >+ } >+ >+ if (!m_set.add(to)) >+ return; >+ >+ if (m_set.size() > polymorphismLimit) >+ makeTop(); >+} >+ >+void StructureAbstractValue::observeTransitions(const TransitionVector& vector) >+{ >+ if (isTop()) >+ return; >+ >+ StructureSet newStructures; >+ for (unsigned i = vector.size(); i--;) { >+ if (!m_set.contains(vector[i].previous)) >+ continue; >+ >+ if (vector[i].previous->transitionWatchpointSetIsStillValid()) >+ 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) >+{ >+ 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) >+{ >+ if (isTop()) >+ return false; >+ >+ return mergeNotTop(other); >+} >+ >+bool StructureAbstractValue::merge(const StructureAbstractValue& other) >+{ >+ if (isTop()) >+ return false; >+ >+ if (other.isTop()) { >+ makeTop(); >+ return true; >+ } >+ >+ // 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) >+{ >+ if (!m_set.merge(other)) >+ return false; >+ >+ if (m_set.size() > polymorphismLimit) >+ makeTop(); >+ >+ return true; >+} >+ >+void StructureAbstractValue::filter(const StructureSet& other) >+{ >+ 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) >+{ >+ 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::filter(SpeculatedType type) >+{ >+ if (!(type & SpecCell)) { >+ clear(); >+ return; >+ } >+ >+ if (isTop()) >+ return; >+ >+ ConformsToType conformsToType(type); >+ m_set.genericFilter(conformsToType); >+} >+ >+bool StructureAbstractValue::contains(Structure* structure) const >+{ >+ if (isTop() || isClobbered()) >+ return true; >+ >+ return m_set.contains(structure); >+} >+ >+bool StructureAbstractValue::isSubsetOf(const StructureSet& other) const >+{ >+ if (isTop() || isClobbered()) >+ return false; >+ >+ return m_set.isSubsetOf(other); >+} >+ >+bool StructureAbstractValue::isSubsetOf(const StructureAbstractValue& other) const >+{ >+ 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 >+{ >+ if (isTop() || isClobbered()) >+ return true; >+ >+ return m_set.isSupersetOf(other); >+} >+ >+bool StructureAbstractValue::overlaps(const StructureSet& other) const >+{ >+ if (isTop() || isClobbered()) >+ return true; >+ >+ return m_set.overlaps(other); >+} >+ >+bool StructureAbstractValue::overlaps(const StructureAbstractValue& other) const >+{ >+ if (other.isTop() || other.isClobbered()) >+ return true; >+ >+ return overlaps(other.m_set); >+} >+ >+bool StructureAbstractValue::operator==(const StructureAbstractValue& other) const >+{ >+ if (m_set.m_pointer == other.m_set.m_pointer) >+ return true; >+ >+ if (isTop() || other.isTop()) >+ return false; // They can't be both top because then their pointer values would have been identical, above. >+ >+ return m_set == other.m_set >+ && isClobbered() == other.isClobbered(); >+} >+ >+void StructureAbstractValue::dumpInContext(PrintStream& out, DumpContext* context) const >+{ >+ if (isClobbered()) >+ out.print("Clobbered:"); >+ >+ if (isTop()) >+ out.print("TOP"); >+ else >+ out.print(inContext(m_set, context)); >+} >+ >+void StructureAbstractValue::dump(PrintStream& out) const >+{ >+ dumpInContext(out, 0); >+} >+ >+} } // namespace JSC::DFG >+ >+#endif // ENABLE(DFG_JIT) >+ >Index: Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h (working copy) >@@ -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,139 @@ namespace JSC { namespace DFG { > > class StructureAbstractValue { > public: >- StructureAbstractValue() >- : m_structure(0) >- { >- } >- >+ StructureAbstractValue() { } > StructureAbstractValue(Structure* structure) >- : m_structure(structure) >- { >- } >- >- StructureAbstractValue(const StructureSet& set) >- { >- switch (set.size()) { >- case 0: >- m_structure = 0; >- break; >- >- case 1: >- m_structure = set[0]; >- break; >- >- default: >- m_structure = topValue(); >- break; >- } >- } >- >- void clear() >- { >- m_structure = 0; >- } >- >- void makeTop() >- { >- m_structure = topValue(); >- } >- >- static StructureAbstractValue top() >- { >- StructureAbstractValue value; >- value.makeTop(); >- return value; >- } >- >- void add(Structure* structure) >+ : m_set(structure) > { >- ASSERT(!contains(structure) && !isTop()); >- if (m_structure) >- makeTop(); >- else >- m_structure = structure; > } >- >- bool addAll(const StructureSet& other) >+ StructureAbstractValue(const StructureSet& other) >+ : m_set(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; > } >+ StructureAbstractValue(const StructureAbstractValue& other); > >- bool addAll(const StructureAbstractValue& other) >- { >- if (!other.m_structure) >- return false; >- if (isTop()) >- return false; >- if (other.isTop()) { >- makeTop(); >- return true; >- } >- if (m_structure) { >- if (m_structure == other.m_structure) >- return false; >- makeTop(); >- return true; >- } >- m_structure = other.m_structure; >- return true; >- } >+ StructureAbstractValue& operator=(const StructureAbstractValue& other); > >- bool contains(Structure* structure) const >+ void clear() > { >- if (isTop()) >- return true; >- if (m_structure == structure) >- return true; >- return false; >+ m_set.clear(); >+ setClobbered(false); > } > >- bool isSubsetOf(const StructureSet& other) const >- { >- if (isTop()) >- return false; >- if (!m_structure) >- return true; >- return other.contains(m_structure); >- } >+ void makeTop(); > >- bool doesNotContainAnyOtherThan(Structure* structure) const >- { >- if (isTop()) >- return false; >- if (!m_structure) >- return true; >- return m_structure == structure; >- } >+#if ASSERT_DISABLED >+ void assertIsWatched(Graph&) const { } >+#else >+ void assertIsWatched(Graph&) const; >+#endif > >- 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]; >- } >+ void clobber(); >+ void observeInvalidationPoint() { setClobbered(false); } > >- 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; >- } >+ void observeTransition(Structure* from, Structure* to); >+ void observeTransitions(const TransitionVector&); > >- 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; >- } >- >- 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(SpeculatedType other) >- { >- if (!(other & SpecCell)) { >- clear(); >- return; >- } >- >- if (isClearOrTop()) >- return; >- >- if (!(speculationFromStructure(m_structure) & other)) >- m_structure = 0; >- } >- >- bool isClear() const >+ static StructureAbstractValue top() > { >- return !m_structure; >- } >- >- bool isTop() const { return m_structure == topValue(); } >+ StructureAbstractValue result; >+ result.m_set.m_pointer = topValue; >+ return result; >+ } >+ >+ bool isClear() const { return m_set.isEmpty(); } >+ bool isTop() const { return m_set.m_pointer == topValue; } >+ bool isNeitherClearNorTop() const { return !isClear() && !isTop(); } >+ >+ // A clobbered abstract value means that the set currently contains the m_set set of >+ // structures plus TOP, except that TOP will go away at the next invalidation point. Note >+ // that intuitively you can sometimes 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 TOP. >+ bool isClobbered() const { return m_set.getReservedFlag(); } >+ >+ bool add(Structure* structure); >+ >+ bool merge(const StructureSet& other); >+ bool merge(const StructureAbstractValue& other); >+ void filter(const StructureSet& other); >+ void filter(const StructureAbstractValue& other); >+ void filter(SpeculatedType type); > >- bool isClearOrTop() const { return m_structure <= topValue(); } >- bool isNeitherClearNorTop() const { return !isClearOrTop(); } >+ bool operator==(const StructureAbstractValue& other) const; > > size_t size() const > { > ASSERT(!isTop()); >- return !!m_structure; >+ return m_set.size(); > } > > Structure* at(size_t i) const > { > ASSERT(!isTop()); >- ASSERT(m_structure); >- ASSERT_UNUSED(i, !i); >- return m_structure; >+ return m_set.at(i); > } > >- Structure* operator[](size_t i) const >- { >- return at(i); >- } >+ Structure* operator[](size_t i) const { return at(i); } > >- Structure* last() const >+ // FIXME: Eliminate all uses of this method. There shouldn't be any >+ // special-casing for the one-structure case. >+ // https://bugs.webkit.org/show_bug.cgi?id=133229 >+ Structure* onlyStructure() const > { >+ if (isTop() || size() != 1) >+ return nullptr; > return at(0); > } > >- SpeculatedType speculationFromStructures() const >- { >- if (isTop()) >- return SpecCell; >- if (isClear()) >- return SpecNone; >- return speculationFromStructure(m_structure); >- } >+ void dumpInContext(PrintStream&, DumpContext*) const; >+ void dump(PrintStream&) const; > >- bool isValidOffset(PropertyOffset offset) >- { >- if (isTop()) >- return false; >- if (isClear()) >- return true; >- return m_structure->isValidOffset(offset); >- } >+ // The methods below are all conservative and err on the side of making 'this' appear bigger >+ // than it is. For example, contains() may return true if the set is clobbered or TOP. >+ // isSubsetOf() may return false in case of ambiguities. Therefore you should only perform >+ // optimizations as a consequence of the "this is smaller" return value - so false for >+ // contains(), true for isSubsetOf(), false for isSupersetOf(), and false for overlaps(). >+ >+ bool contains(Structure* structure) const; > >- bool hasSingleton() const >- { >- return isNeitherClearNorTop(); >- } >+ bool isSubsetOf(const StructureSet& other) const; >+ bool isSubsetOf(const StructureAbstractValue& other) const; > >- Structure* singleton() const >+ bool isSupersetOf(const StructureSet& other) const; >+ bool isSupersetOf(const StructureAbstractValue& other) const > { >- ASSERT(isNeitherClearNorTop()); >- return m_structure; >+ return other.isSubsetOf(*this); > } > >- bool operator==(const StructureAbstractValue& other) const >- { >- return m_structure == other.m_structure; >- } >+ bool overlaps(const StructureSet& other) const; >+ bool overlaps(const StructureAbstractValue& other) const; > >- void dumpInContext(PrintStream& out, DumpContext* context) const >+private: >+ static const uintptr_t clobberedFlag = StructureSet::reservedFlag; >+ static const uintptr_t topValue = StructureSet::reservedValue; >+ static const unsigned polymorphismLimit = 10; >+ static const unsigned clobberedSupremacyThreshold = 2; >+ >+ void makeTopWhenThin() > { >- if (isTop()) { >- out.print("TOP"); >- return; >- } >- >- out.print("["); >- if (m_structure) >- out.print(inContext(*m_structure, context)); >- out.print("]"); >+ ASSERT(m_set.isThin()); >+ m_set.m_pointer = topValue; > } >- >- void dump(PrintStream& out) const >+ >+ bool mergeNotTop(const StructureSet& other); >+ >+ void setClobbered(bool clobbered) > { >- dumpInContext(out, 0); >+ ASSERT(!isTop() || !clobbered); >+ m_set.setReservedFlag(clobbered); > } >- >-private: >- static Structure* topValue() { return reinterpret_cast<Structure*>(1); } >- >- // NB. This must have a trivial destructor. > >- // This can only remember one structure at a time. >- Structure* m_structure; >+ StructureSet m_set; > }; > > } } // namespace JSC::DFG >Index: Source/JavaScriptCore/dfg/DFGTransition.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGTransition.cpp (revision 0) >+++ Source/JavaScriptCore/dfg/DFGTransition.cpp (working copy) >@@ -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) >+ >Index: Source/JavaScriptCore/dfg/DFGTransition.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGTransition.h (revision 0) >+++ Source/JavaScriptCore/dfg/DFGTransition.h (working copy) >@@ -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 >+ >Index: Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp (working copy) >@@ -215,8 +215,7 @@ private: > 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 @@ private: > noticeStructureCheck(variable, subNode->structureSet()); > break; > } >- case StructureTransitionWatchpoint: { >- if (subNode->child1() != source) >- break; >- >- noticeStructureCheck(variable, subNode->structure()); >- break; >- } > default: > break; > } >@@ -331,7 +323,6 @@ private: > } > > case CheckStructure: >- case StructureTransitionWatchpoint: > case GetByOffset: > case PutByOffset: > case PutStructure: >@@ -386,13 +377,6 @@ private: > noticeStructureCheckAccountingForArrayMode(variable, subNode->structureSet()); > break; > } >- case StructureTransitionWatchpoint: { >- if (subNode->child1() != source) >- break; >- >- noticeStructureCheckAccountingForArrayMode(variable, subNode->structure()); >- break; >- } > case CheckArray: { > if (subNode->child1() != source) > break; >Index: Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp (revision 0) >+++ Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp (working copy) >@@ -0,0 +1,180 @@ >+/* >+ * 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) >+ { >+ if (structure->transitionWatchpointSetIsStillValid()) >+ m_graph.watchpoints().addLazily(structure->transitionWatchpointSet()); >+ } >+}; >+ >+bool performWatchableStructureWatching(Graph& graph) >+{ >+ SamplingRegion samplingRegion("DFG Watchable Structure Watching"); >+ return runPhase<WatchableStructureWatchingPhase>(graph); >+} >+ >+} } // namespace JSC::DFG >+ >+#endif // ENABLE(DFG_JIT) >+ >Index: Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.h (revision 0) >+++ Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.h (working copy) >@@ -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 >+ >Index: Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp (revision 169200) >+++ Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp (working copy) >@@ -119,13 +119,6 @@ private: > 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; >@@ -154,11 +147,8 @@ private: > 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()); >+ m_graph.watchpoints().addLazily(stringPrototypeStructure->transitionWatchpointSet()); > break; > } > >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 169200) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -63,7 +63,6 @@ inline CapabilityLevel canCompile(Node* > case BitLShift: > case BitURShift: > case CheckStructure: >- case StructureTransitionWatchpoint: > case ArrayifyToStructure: > case PutStructure: > case PhantomPutStructure: >Index: Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h (revision 169200) >+++ Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h (working copy) >@@ -82,12 +82,15 @@ namespace JSC { namespace FTL { > macro(S_JITOperation_EJ, functionType(intPtr, intPtr, int64)) \ > macro(S_JITOperation_EJJ, functionType(intPtr, intPtr, int64, int64)) \ > macro(S_JITOperation_J, functionType(intPtr, int64)) \ >+ macro(V_JITOperation, functionType(voidType)) \ > macro(V_JITOperation_EJJJ, functionType(voidType, intPtr, int64, int64, int64)) \ > macro(V_JITOperation_EOZD, functionType(voidType, intPtr, intPtr, int32, doubleType)) \ > macro(V_JITOperation_EOZJ, functionType(voidType, intPtr, intPtr, int32, int64)) \ > 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 { >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 169200) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -258,6 +258,7 @@ private: > bool compileNode(unsigned nodeIndex) > { > if (!m_state.isValid()) { >+ m_out.trap(); > m_out.unreachable(); > return false; > } >@@ -399,9 +400,6 @@ private: > case CheckStructure: > compileCheckStructure(); > break; >- case StructureTransitionWatchpoint: >- compileStructureTransitionWatchpoint(); >- break; > case CheckFunction: > compileCheckFunction(); > break; >@@ -1609,12 +1607,6 @@ private: > m_out.appendTo(continuation, lastNext); > } > >- void compileStructureTransitionWatchpoint() >- { >- addWeakReference(m_node->structure()); >- speculateCell(m_node->child1()); >- } >- > void compileCheckFunction() > { > LValue cell = lowCell(m_node->child1()); >@@ -1700,8 +1692,8 @@ private: > { > 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()); >@@ -2791,21 +2783,19 @@ private: > > 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() >@@ -3207,7 +3197,7 @@ private: > } > > m_out.appendTo(exit, continuation); >- terminate(BadCache); >+ speculate(BadCache, noValue(), nullptr, m_out.booleanTrue); > m_out.unreachable(); > > m_out.appendTo(continuation, lastNext); >@@ -3279,7 +3269,7 @@ private: > } > > m_out.appendTo(exit, continuation); >- terminate(BadCache); >+ speculate(BadCache, noValue(), nullptr, m_out.booleanTrue); > m_out.unreachable(); > > m_out.appendTo(continuation, lastNext); >@@ -4718,7 +4708,8 @@ private: > > void terminate(ExitKind kind) > { >- speculate(kind, noValue(), 0, m_out.booleanTrue); >+ speculate(kind, noValue(), nullptr, m_out.booleanTrue); >+ m_state.setIsValid(false); > } > > void typeCheck( >@@ -5463,7 +5454,7 @@ private: > 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( >@@ -5667,9 +5658,10 @@ private: > > 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); > } >Index: Source/JavaScriptCore/jit/JITOperations.h >=================================================================== >--- Source/JavaScriptCore/jit/JITOperations.h (revision 169200) >+++ Source/JavaScriptCore/jit/JITOperations.h (working copy) >@@ -140,6 +140,7 @@ typedef size_t JIT_OPERATION (*S_JITOper > typedef size_t JIT_OPERATION (*S_JITOperation_EOJss)(ExecState*, JSObject*, JSString*); > typedef size_t JIT_OPERATION (*S_JITOperation_J)(EncodedJSValue); > typedef SlowPathReturnType JIT_OPERATION (*Sprt_JITOperation_EZ)(ExecState*, int32_t); >+typedef void JIT_OPERATION (*V_JITOperation)(); > typedef void JIT_OPERATION (*V_JITOperation_E)(ExecState*); > typedef void JIT_OPERATION (*V_JITOperation_EC)(ExecState*, JSCell*); > typedef void JIT_OPERATION (*V_JITOperation_ECb)(ExecState*, CodeBlock*); >@@ -167,6 +168,8 @@ typedef void JIT_OPERATION (*V_JITOperat > 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*); >Index: Source/JavaScriptCore/tests/stress/arrayify-to-structure-contradiction.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/arrayify-to-structure-contradiction.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/arrayify-to-structure-contradiction.js (working copy) >@@ -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; >+} >+ >Index: Source/JavaScriptCore/tests/stress/ftl-getmyargumentslength-inline.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/ftl-getmyargumentslength-inline.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/ftl-getmyargumentslength-inline.js (working copy) >@@ -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; >+} >+ >Index: Source/JavaScriptCore/tests/stress/multi-put-by-offset-multiple-transitions.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/multi-put-by-offset-multiple-transitions.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/multi-put-by-offset-multiple-transitions.js (working copy) >@@ -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; >+ >Index: Source/JavaScriptCore/tests/stress/throw-from-ftl-in-loop.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/throw-from-ftl-in-loop.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/throw-from-ftl-in-loop.js (working copy) >@@ -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."; >Index: Source/JavaScriptCore/tests/stress/throw-from-ftl.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/throw-from-ftl.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/throw-from-ftl.js (working copy) >@@ -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."; >Index: Source/WTF/ChangeLog >=================================================================== >--- Source/WTF/ChangeLog (revision 169515) >+++ Source/WTF/ChangeLog (working copy) >@@ -1,3 +1,14 @@ >+2014-06-01 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 NOBODY (OOPS!). >+ >+ * wtf/Bag.h: >+ (WTF::Bag::Node::Node): >+ (WTF::Bag::add): >+ > 2014-05-19 Filip Pizlo <fpizlo@apple.com> > > [ftlopt] DFG bytecode parser should turn GetById with nothing but a Getter stub as stuff+handleCall, and handleCall should be allowed to inline if it wants to >Index: Source/WTF/wtf/Bag.h >=================================================================== >--- Source/WTF/wtf/Bag.h (revision 169200) >+++ Source/WTF/wtf/Bag.h (working copy) >@@ -34,6 +34,12 @@ private: > 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 @@ public: > } > } > >- 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; >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 169515) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,23 @@ >+2014-06-01 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 NOBODY (OOPS!). >+ >+ * 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-05-21 Filip Pizlo <fpizlo@apple.com> > > [ftlopt] DFG::clobberize should be blind to the effects of GC >Index: LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-expected.txt >=================================================================== >--- LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-expected.txt (revision 0) >+++ LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-expected.txt (working copy) >@@ -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 >+ >Index: LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple-expected.txt >=================================================================== >--- LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple-expected.txt (revision 0) >+++ LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple-expected.txt (working copy) >@@ -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 >+ >Index: LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple.html >=================================================================== >--- LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple.html (revision 0) >+++ LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination-simple.html (working copy) >@@ -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> >Index: LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination.html >=================================================================== >--- LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination.html (revision 0) >+++ LayoutTests/js/regress/get-by-id-bimorphic-check-structure-elimination.html (working copy) >@@ -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> >Index: LayoutTests/js/regress/get-by-id-check-structure-elimination-expected.txt >=================================================================== >--- LayoutTests/js/regress/get-by-id-check-structure-elimination-expected.txt (revision 0) >+++ LayoutTests/js/regress/get-by-id-check-structure-elimination-expected.txt (working copy) >@@ -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 >+ >Index: LayoutTests/js/regress/get-by-id-check-structure-elimination.html >=================================================================== >--- LayoutTests/js/regress/get-by-id-check-structure-elimination.html (revision 0) >+++ LayoutTests/js/regress/get-by-id-check-structure-elimination.html (working copy) >@@ -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> >Index: LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple-expected.txt >=================================================================== >--- LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple-expected.txt (revision 0) >+++ LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple-expected.txt (working copy) >@@ -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 >+ >Index: LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple.html >=================================================================== >--- LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple.html (revision 0) >+++ LayoutTests/js/regress/get-by-id-quadmorphic-check-structure-elimination-simple.html (working copy) >@@ -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> >Index: LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination-simple.js >=================================================================== >--- LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination-simple.js (revision 0) >+++ LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination-simple.js (working copy) >@@ -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; >+})(); >Index: LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination.js >=================================================================== >--- LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination.js (revision 0) >+++ LayoutTests/js/regress/script-tests/get-by-id-bimorphic-check-structure-elimination.js (working copy) >@@ -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; >+})(); >Index: LayoutTests/js/regress/script-tests/get-by-id-check-structure-elimination.js >=================================================================== >--- LayoutTests/js/regress/script-tests/get-by-id-check-structure-elimination.js (revision 0) >+++ LayoutTests/js/regress/script-tests/get-by-id-check-structure-elimination.js (working copy) >@@ -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; >+})(); >Index: LayoutTests/js/regress/script-tests/get-by-id-quadmorphic-check-structure-elimination-simple.js >=================================================================== >--- LayoutTests/js/regress/script-tests/get-by-id-quadmorphic-check-structure-elimination-simple.js (revision 0) >+++ LayoutTests/js/regress/script-tests/get-by-id-quadmorphic-check-structure-elimination-simple.js (working copy) >@@ -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; >+})();
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 128073
:
231915
|
231935
|
231983
|
232228
|
232232
|
232264
|
232270
|
232281
|
232304
|
232349
|
232350
|
232413
|
232437
|
232449
|
232460