diff options
Diffstat (limited to 'Source/JavaScriptCore')
34 files changed, 1827 insertions, 1612 deletions
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index 9c18f5b03..2689bce5c 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -66,6 +66,7 @@ SET(JavaScriptCore_SOURCES dfg/DFGAbstractState.cpp dfg/DFGArgumentsSimplificationPhase.cpp + dfg/DFGArrayMode.cpp dfg/DFGAssemblyHelpers.cpp dfg/DFGByteCodeParser.cpp dfg/DFGCapabilities.cpp @@ -107,6 +108,7 @@ SET(JavaScriptCore_SOURCES heap/CopiedSpace.cpp heap/ConservativeRoots.cpp heap/DFGCodeBlocks.cpp + heap/GCThreadSharedData.cpp heap/HandleSet.cpp heap/HandleStack.cpp heap/Heap.cpp diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index ac3aae5ff..987ca8ecf 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,171 @@ +2012-08-22 Filip Pizlo <fpizlo@apple.com> + + Array accesses should remember what kind of array they are predicted to access + https://bugs.webkit.org/show_bug.cgi?id=94448 + + Reviewed by Gavin Barraclough. + + Introduced the notion of DFG::Array::Mode, stored in node.arrayMode(), which allows nodes + to remember how they decided to access arrays. This permits the bytecode parser to "lock in" + the mode of access if it has profiling at its disposal, and it also allows the prediction + propagator to do a fixup of the array mode later in the optimization fixpoint. + + This patch adds a healthy amount of new capability (specifically the ability of the parser + to lock in an array mode regardless of type predictions) and it also blows away a lot of + messy code. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGArrayMode.cpp: Added. + (DFG): + (JSC::DFG::fromObserved): + (JSC::DFG::refineArrayMode): + (JSC::DFG::modeAlreadyChecked): + (JSC::DFG::modeToString): + * dfg/DFGArrayMode.h: Added. + (DFG): + (JSC::DFG::canCSEStorage): + (JSC::DFG::modeForPut): + (JSC::DFG::modesCompatibleForStorageLoad): + (JSC::DFG::modeSupportsLength): + * dfg/DFGByteCodeParser.cpp: + (ByteCodeParser): + (JSC::DFG::ByteCodeParser::getArrayModeWithoutOSRExit): + (JSC::DFG::ByteCodeParser::getArrayMode): + (JSC::DFG::ByteCodeParser::handleIntrinsic): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::getByValLoadElimination): + (JSC::DFG::CSEPhase::checkStructureLoadElimination): + (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination): + (JSC::DFG::CSEPhase::getByOffsetLoadElimination): + (JSC::DFG::CSEPhase::putByOffsetStoreElimination): + (JSC::DFG::CSEPhase::getPropertyStorageLoadElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::byValIsPure): + (JSC::DFG::Graph::clobbersWorld): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasArrayMode): + (Node): + (JSC::DFG::Node::arrayMode): + (JSC::DFG::Node::setArrayMode): + * dfg/DFGNodeType.h: + (DFG): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::typedArrayDescriptor): + (DFG): + (JSC::DFG::SpeculativeJIT::speculateArray): + (JSC::DFG::SpeculativeJIT::compileGetByValOnString): + (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray): + (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray): + (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): + (JSC::DFG::SpeculativeJIT::compilePutByValForFloatTypedArray): + (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage): + (JSC::DFG::SpeculativeJIT::compileGetArrayLength): + * dfg/DFGSpeculativeJIT.h: + (SpeculativeJIT): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureCheckHoistingPhase.cpp: + (JSC::DFG::StructureCheckHoistingPhase::run): + +2012-08-22 Geoffrey Garen <ggaren@apple.com> + + ThreadRestrictionVerifier should be opt-in, not opt-out + https://bugs.webkit.org/show_bug.cgi?id=94761 + + Reviewed by Mark Hahnenberg. + + Removed explicit calls to disable the verifier, since it's off by default now. + + * parser/SourceProvider.h: + (JSC::SourceProvider::SourceProvider): + (SourceProvider): + * runtime/SymbolTable.h: + (JSC::SharedSymbolTable::SharedSymbolTable): + +2012-08-22 Mark Hahnenberg <mhahnenberg@apple.com> + + Separate MarkStackThreadSharedData from MarkStack + https://bugs.webkit.org/show_bug.cgi?id=94294 + + Reviewed by Filip Pizlo. + + MarkStackThreadSharedData is soon going to have data to allow for a parallel copying + mode too, so to separate our concerns we should split it out into its own set of files + and rename it to GCThreadSharedData. For now this is purely a cosmetic refactoring. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * heap/GCThreadSharedData.cpp: Added. + (JSC): + (JSC::GCThreadSharedData::resetChildren): + (JSC::GCThreadSharedData::childVisitCount): + (JSC::GCThreadSharedData::markingThreadMain): + (JSC::GCThreadSharedData::markingThreadStartFunc): + (JSC::GCThreadSharedData::GCThreadSharedData): + (JSC::GCThreadSharedData::~GCThreadSharedData): + (JSC::GCThreadSharedData::reset): + * heap/GCThreadSharedData.h: Added. + (JSC): + (GCThreadSharedData): + * heap/Heap.h: + (Heap): + * heap/ListableHandler.h: + (ListableHandler): + * heap/MarkStack.cpp: + (JSC::MarkStack::MarkStack): + (JSC::MarkStack::~MarkStack): + * heap/MarkStack.h: + (JSC): + (MarkStack): + (JSC::MarkStack::sharedData): + * heap/MarkStackInlineMethods.h: Added. + (JSC): + (JSC::MarkStack::append): + (JSC::MarkStack::appendUnbarrieredPointer): + (JSC::MarkStack::appendUnbarrieredValue): + (JSC::MarkStack::internalAppend): + (JSC::MarkStack::addWeakReferenceHarvester): + (JSC::MarkStack::addUnconditionalFinalizer): + (JSC::MarkStack::addOpaqueRoot): + (JSC::MarkStack::containsOpaqueRoot): + (JSC::MarkStack::opaqueRootCount): + * heap/SlotVisitor.h: + (JSC): + (SlotVisitor): + (JSC::SlotVisitor::SlotVisitor): + +2012-08-22 Gabor Ballabas <gaborb@inf.u-szeged.hu> + + Fix JSC build when DFG-JIT is disabled + https://bugs.webkit.org/show_bug.cgi?id=94694 + + Reviewed by Csaba Osztrogonác. + + Adding an appropriate guard for fixing the build. + + * bytecode/ResolveGlobalStatus.cpp: + (JSC): + 2012-08-21 Mark Lam <mark.lam@apple.com> Introducing the VMInspector for VM debugging use. diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index ed79e6873..b0c31599c 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -155,6 +155,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/dfg/DFGArgumentPosition.h \ Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp \ Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.h \ + Source/JavaScriptCore/dfg/DFGArrayMode.cpp \ + Source/JavaScriptCore/dfg/DFGArrayMode.h \ Source/JavaScriptCore/dfg/DFGAssemblyHelpers.cpp \ Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h \ Source/JavaScriptCore/dfg/DFGBasicBlock.h \ @@ -273,6 +275,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/heap/HandleTypes.h \ Source/JavaScriptCore/heap/BlockAllocator.cpp \ Source/JavaScriptCore/heap/BlockAllocator.h \ + Source/JavaScriptCore/heap/GCThreadSharedData.cpp \ + Source/JavaScriptCore/heap/GCThreadSharedData.h \ Source/JavaScriptCore/heap/Heap.cpp \ Source/JavaScriptCore/heap/Heap.h \ Source/JavaScriptCore/heap/JITStubRoutineSet.cpp \ @@ -284,6 +288,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/heap/MachineStackMarker.h \ Source/JavaScriptCore/heap/MarkStack.cpp \ Source/JavaScriptCore/heap/MarkStack.h \ + Source/JavaScriptCore/heap/MarkStackInlineMethods.h \ Source/JavaScriptCore/heap/HeapRootVisitor.h \ Source/JavaScriptCore/heap/MarkedAllocator.cpp \ Source/JavaScriptCore/heap/MarkedAllocator.h \ diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj index 8695a7557..78c44feb5 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -2326,6 +2326,14 @@ > </File> <File + RelativePath="..\..\heap\GCThreadSharedData.cpp" + > + </File> + <File + RelativePath="..\..\heap\GCThreadSharedData.h" + > + </File> + <File RelativePath="..\..\heap\Heap.cpp" > </File> @@ -2390,6 +2398,10 @@ > </File> <File + RelativePath="..\..\heap\MarkStackInlineMethods.h" + > + </File> + <File RelativePath="..\..\heap\Strong.h" > </File> diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 7dd87fee0..da029cc08 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -142,6 +142,8 @@ 0F63944015C75F1D006A597C /* DFGStructureCheckHoistingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63943C15C75F14006A597C /* DFGStructureCheckHoistingPhase.cpp */; }; 0F63945415D07055006A597C /* ArrayProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63945115D07051006A597C /* ArrayProfile.cpp */; }; 0F63945515D07057006A597C /* ArrayProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63945215D07051006A597C /* ArrayProfile.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F63948415E48118006A597C /* DFGArrayMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63948115E48114006A597C /* DFGArrayMode.cpp */; }; + 0F63948515E4811B006A597C /* DFGArrayMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63948215E48114006A597C /* DFGArrayMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F63947815DCE34B006A597C /* DFGStructureAbstractValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F66E16B14DF3F1600B7B2E4 /* DFGAdjacencyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F66E16C14DF3F1600B7B2E4 /* DFGEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -690,6 +692,9 @@ BCF605140E203EF800B9A64D /* ArgList.h in Headers */ = {isa = PBXBuildFile; fileRef = BCF605120E203EF800B9A64D /* ArgList.h */; settings = {ATTRIBUTES = (Private, ); }; }; BCFD8C920EEB2EE700283848 /* JumpTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCFD8C900EEB2EE700283848 /* JumpTable.cpp */; }; BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFD8C910EEB2EE700283848 /* JumpTable.h */; }; + C21122E115DD9AB300790E3A /* GCThreadSharedData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */; }; + C21122E215DD9AB300790E3A /* GCThreadSharedData.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C21122E315DD9AB300790E3A /* MarkStackInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; C22B31B9140577D700DB475A /* SamplingCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F77008E1402FDD60078EB39 /* SamplingCounter.h */; settings = {ATTRIBUTES = (Private, ); }; }; C240305514B404E60079EB64 /* CopiedSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C240305314B404C90079EB64 /* CopiedSpace.cpp */; }; C25F8BCD157544A900245B71 /* IncrementalSweeper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */; }; @@ -896,6 +901,8 @@ 0F63943D15C75F14006A597C /* DFGStructureCheckHoistingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureCheckHoistingPhase.h; path = dfg/DFGStructureCheckHoistingPhase.h; sourceTree = "<group>"; }; 0F63945115D07051006A597C /* ArrayProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayProfile.cpp; sourceTree = "<group>"; }; 0F63945215D07051006A597C /* ArrayProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayProfile.h; sourceTree = "<group>"; }; + 0F63948115E48114006A597C /* DFGArrayMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGArrayMode.cpp; path = dfg/DFGArrayMode.cpp; sourceTree = "<group>"; }; + 0F63948215E48114006A597C /* DFGArrayMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArrayMode.h; path = dfg/DFGArrayMode.h; sourceTree = "<group>"; }; 0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureAbstractValue.h; path = dfg/DFGStructureAbstractValue.h; sourceTree = "<group>"; }; 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAdjacencyList.h; path = dfg/DFGAdjacencyList.h; sourceTree = "<group>"; }; 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGEdge.h; path = dfg/DFGEdge.h; sourceTree = "<group>"; }; @@ -1447,6 +1454,9 @@ BCF605120E203EF800B9A64D /* ArgList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArgList.h; sourceTree = "<group>"; }; BCFD8C900EEB2EE700283848 /* JumpTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JumpTable.cpp; sourceTree = "<group>"; }; BCFD8C910EEB2EE700283848 /* JumpTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JumpTable.h; sourceTree = "<group>"; }; + C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCThreadSharedData.cpp; sourceTree = "<group>"; }; + C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCThreadSharedData.h; sourceTree = "<group>"; }; + C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStackInlineMethods.h; sourceTree = "<group>"; }; C240305314B404C90079EB64 /* CopiedSpace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CopiedSpace.cpp; sourceTree = "<group>"; }; C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IncrementalSweeper.cpp; sourceTree = "<group>"; }; C25F8BCC157544A900245B71 /* IncrementalSweeper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IncrementalSweeper.h; sourceTree = "<group>"; }; @@ -1772,6 +1782,9 @@ 142E312A134FF0A600AFADB5 /* heap */ = { isa = PBXGroup; children = ( + C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */, + C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */, + C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */, C2E526BB1590EF000054E48D /* HeapTimer.cpp */, C2E526BC1590EF000054E48D /* HeapTimer.h */, C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */, @@ -2257,12 +2270,15 @@ 86EC9DB31328DF44002B2AD7 /* dfg */ = { isa = PBXGroup; children = ( - 0F1E3A431534CBAD000F9456 /* DFGArgumentPosition.h */, - 0F16015A156198BF00C2587C /* DFGArgumentsSimplificationPhase.cpp */, - 0F16015B156198BF00C2587C /* DFGArgumentsSimplificationPhase.h */, 0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */, 0F62016E143FCD2F0068B77C /* DFGAbstractState.h */, 0F62016F143FCD2F0068B77C /* DFGAbstractValue.h */, + 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */, + 0F1E3A431534CBAD000F9456 /* DFGArgumentPosition.h */, + 0F16015A156198BF00C2587C /* DFGArgumentsSimplificationPhase.cpp */, + 0F16015B156198BF00C2587C /* DFGArgumentsSimplificationPhase.h */, + 0F63948115E48114006A597C /* DFGArrayMode.cpp */, + 0F63948215E48114006A597C /* DFGArrayMode.h */, 0FC0976B1468AB4A00CF2442 /* DFGAssemblyHelpers.cpp */, 0FC0976C1468AB4A00CF2442 /* DFGAssemblyHelpers.h */, 0F620170143FCD2F0068B77C /* DFGBasicBlock.h */, @@ -2306,7 +2322,6 @@ 86ECA3E9132DEF1C002B2AD7 /* DFGNode.h */, 0FA581B7150E952A00B9A2D9 /* DFGNodeFlags.cpp */, 0FA581B8150E952A00B9A2D9 /* DFGNodeFlags.h */, - 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */, 0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */, 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */, 86EC9DBF1328DF82002B2AD7 /* DFGOperations.cpp */, @@ -2513,7 +2528,9 @@ 86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */, C2EAD2FC14F0249800A4B159 /* CopiedAllocator.h in Headers */, C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */, + C21122E215DD9AB300790E3A /* GCThreadSharedData.h in Headers */, C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */, + C21122E315DD9AB300790E3A /* MarkStackInlineMethods.h in Headers */, C25F8BCE157544A900245B71 /* IncrementalSweeper.h in Headers */, BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */, BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */, @@ -2884,6 +2901,7 @@ FE4A332015BD2E07006F54F3 /* VMInspector.h in Headers */, 0F63943F15C75F19006A597C /* DFGStructureCheckHoistingPhase.h in Headers */, 0F63945515D07057006A597C /* ArrayProfile.h in Headers */, + 0F63948515E4811B006A597C /* DFGArrayMode.h in Headers */, 0F63947815DCE34B006A597C /* DFGStructureAbstractValue.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3485,6 +3503,8 @@ FE4A331F15BD2E07006F54F3 /* VMInspector.cpp in Sources */, 0F63944015C75F1D006A597C /* DFGStructureCheckHoistingPhase.cpp in Sources */, 0F63945415D07055006A597C /* ArrayProfile.cpp in Sources */, + 0F63948415E48118006A597C /* DFGArrayMode.cpp in Sources */, + C21122E115DD9AB300790E3A /* GCThreadSharedData.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri index e8622363c..c7e41ab3a 100644 --- a/Source/JavaScriptCore/Target.pri +++ b/Source/JavaScriptCore/Target.pri @@ -79,6 +79,7 @@ SOURCES += \ heap/HandleSet.cpp \ heap/HandleStack.cpp \ heap/BlockAllocator.cpp \ + heap/GCThreadSharedData.cpp \ heap/Heap.cpp \ heap/HeapTimer.cpp \ heap/IncrementalSweeper.cpp \ @@ -95,6 +96,7 @@ SOURCES += \ debugger/Debugger.cpp \ dfg/DFGAbstractState.cpp \ dfg/DFGArgumentsSimplificationPhase.cpp \ + dfg/DFGArrayMode.cpp \ dfg/DFGAssemblyHelpers.cpp \ dfg/DFGByteCodeParser.cpp \ dfg/DFGCapabilities.cpp \ diff --git a/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp b/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp index ddc7700c6..783e7c615 100644 --- a/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp +++ b/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp @@ -32,7 +32,7 @@ namespace JSC { -#if ENABLE(LLINT) || ENABLE(JIT) +#if ENABLE(LLINT) || (ENABLE(JIT) && ENABLE(VALUE_PROFILER)) static ResolveGlobalStatus computeForStructure(CodeBlock* codeBlock, Structure* structure, Identifier& identifier) { unsigned attributesIgnored; diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index 5c53f6d78..cfe915947 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -868,65 +868,66 @@ bool AbstractState::execute(unsigned indexInBlock) case GetByVal: { node.setCanExit(true); - if (!node.prediction() || !m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction()) { + switch (node.arrayMode()) { + case Array::Undecided: + ASSERT_NOT_REACHED(); + break; + case Array::ForceExit: m_isValid = false; break; - } - if (!m_graph[node.child2()].shouldSpeculateInteger() || (!node.child3() && !m_graph[node.child1()].shouldSpeculateArguments())) { + case Array::Generic: clobberWorld(node.codeOrigin, indexInBlock); forNode(nodeIndex).makeTop(); break; - } - if (m_graph[node.child1()].shouldSpeculateArguments()) { + case Array::String: + forNode(node.child1()).filter(SpecString); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecString); + break; + case Array::Arguments: forNode(node.child1()).filter(SpecArguments); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).makeTop(); break; - } - if (m_graph[node.child1()].prediction() == SpecString) { - forNode(node.child1()).filter(SpecString); + case Array::JSArray: + case Array::JSArrayOutOfBounds: + // FIXME: We should have more conservative handling of the out-of-bounds + // case. + forNode(node.child1()).filter(SpecCell); forNode(node.child2()).filter(SpecInt32); - forNode(nodeIndex).set(SpecString); + forNode(nodeIndex).makeTop(); break; - } - - if (m_graph[node.child1()].shouldSpeculateInt8Array()) { + case Array::Int8Array: forNode(node.child1()).filter(SpecInt8Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateInt16Array()) { + case Array::Int16Array: forNode(node.child1()).filter(SpecInt16Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateInt32Array()) { + case Array::Int32Array: forNode(node.child1()).filter(SpecInt32Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateUint8Array()) { + case Array::Uint8Array: forNode(node.child1()).filter(SpecUint8Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { + case Array::Uint8ClampedArray: forNode(node.child1()).filter(SpecUint8ClampedArray); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateUint16Array()) { + case Array::Uint16Array: forNode(node.child1()).filter(SpecUint16Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateUint32Array()) { + case Array::Uint32Array: forNode(node.child1()).filter(SpecUint32Array); forNode(node.child2()).filter(SpecInt32); if (node.shouldSpeculateInteger()) @@ -934,55 +935,47 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(nodeIndex).set(SpecDouble); break; - } - if (m_graph[node.child1()].shouldSpeculateFloat32Array()) { + case Array::Float32Array: forNode(node.child1()).filter(SpecFloat32Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecDouble); break; - } - if (m_graph[node.child1()].shouldSpeculateFloat64Array()) { + case Array::Float64Array: forNode(node.child1()).filter(SpecFloat64Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecDouble); break; } - forNode(node.child1()).filter(SpecCell); - forNode(node.child2()).filter(SpecInt32); - forNode(nodeIndex).makeTop(); break; } case PutByVal: - case PutByValAlias: - case PutByValSafe: { + case PutByValAlias: { node.setCanExit(true); - Edge child1 = m_graph.varArgChild(node, 0); Edge child2 = m_graph.varArgChild(node, 1); Edge child3 = m_graph.varArgChild(node, 2); - - if (!m_graph[child1].prediction() || !m_graph[child2].prediction()) { + switch (modeForPut(node.arrayMode())) { + case Array::ForceExit: m_isValid = false; break; - } - if (!m_graph[child2].shouldSpeculateInteger() -#if USE(JSVALUE32_64) - || m_graph[child1].shouldSpeculateArguments() -#endif - ) { - ASSERT(node.op() == PutByVal || node.op() == PutByValSafe); + case Array::Generic: clobberWorld(node.codeOrigin, indexInBlock); - forNode(nodeIndex).makeTop(); break; - } - - if (m_graph[child1].shouldSpeculateArguments()) { + case Array::JSArray: + forNode(child1).filter(SpecCell); + forNode(child2).filter(SpecInt32); + break; + case Array::JSArrayOutOfBounds: + forNode(child1).filter(SpecCell); + forNode(child2).filter(SpecInt32); + clobberWorld(node.codeOrigin, indexInBlock); + break; + case Array::Arguments: forNode(child1).filter(SpecArguments); forNode(child2).filter(SpecInt32); break; - } - if (m_graph[child1].shouldSpeculateInt8Array()) { + case Array::Int8Array: forNode(child1).filter(SpecInt8Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -990,8 +983,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateInt16Array()) { + case Array::Int16Array: forNode(child1).filter(SpecInt16Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -999,8 +991,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateInt32Array()) { + case Array::Int32Array: forNode(child1).filter(SpecInt32Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -1008,8 +999,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateUint8Array()) { + case Array::Uint8Array: forNode(child1).filter(SpecUint8Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -1017,8 +1007,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateUint8ClampedArray()) { + case Array::Uint8ClampedArray: forNode(child1).filter(SpecUint8ClampedArray); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -1026,8 +1015,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateUint16Array()) { + case Array::Uint16Array: forNode(child1).filter(SpecUint16Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -1035,8 +1023,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateUint32Array()) { + case Array::Uint32Array: forNode(child1).filter(SpecUint32Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -1044,23 +1031,20 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateFloat32Array()) { + case Array::Float32Array: forNode(child1).filter(SpecFloat32Array); forNode(child2).filter(SpecInt32); forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateFloat64Array()) { + case Array::Float64Array: forNode(child1).filter(SpecFloat64Array); forNode(child2).filter(SpecInt32); forNode(child3).filter(SpecNumber); break; + default: + ASSERT_NOT_REACHED(); + break; } - forNode(child1).filter(SpecCell); - forNode(child2).filter(SpecInt32); - if (node.op() == PutByValSafe) - clobberWorld(node.codeOrigin, indexInBlock); break; } @@ -1356,69 +1340,82 @@ bool AbstractState::execute(unsigned indexInBlock) break; case GetArrayLength: - node.setCanExit(true); - forNode(node.child1()).filter(SpecCell); - forNode(nodeIndex).set(SpecInt32); - break; - - case GetArgumentsLength: - node.setCanExit(true); - forNode(node.child1()).filter(SpecArguments); - forNode(nodeIndex).set(SpecInt32); + switch (node.arrayMode()) { + case Array::Undecided: + ASSERT_NOT_REACHED(); + break; + case Array::ForceExit: + m_isValid = false; + break; + case Array::Generic: + ASSERT_NOT_REACHED(); + break; + case Array::String: + node.setCanExit(!isStringSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecString); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::JSArray: + node.setCanExit(true); + forNode(node.child1()).filter(SpecCell); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::JSArrayOutOfBounds: + ASSERT_NOT_REACHED(); + break; + case Array::Arguments: + node.setCanExit(true); + forNode(node.child1()).filter(SpecArguments); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Int8Array: + node.setCanExit(!isInt8ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt8Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Int16Array: + node.setCanExit(!isInt16ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt16Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Int32Array: + node.setCanExit(!isInt32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt32Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Uint8Array: + node.setCanExit(!isUint8ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint8Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Uint8ClampedArray: + node.setCanExit(!isUint8ClampedArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint8ClampedArray); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Uint16Array: + node.setCanExit(!isUint16ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint16Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Uint32Array: + node.setCanExit(!isUint32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint32Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Float32Array: + node.setCanExit(!isFloat32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFloat32Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Float64Array: + node.setCanExit(!isFloat64ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFloat64Array); + forNode(nodeIndex).set(SpecInt32); + break; + } break; - case GetStringLength: - node.setCanExit(!isStringSpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecString); - forNode(nodeIndex).set(SpecInt32); - break; - - case GetInt8ArrayLength: - node.setCanExit(!isInt8ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecInt8Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetInt16ArrayLength: - node.setCanExit(!isInt16ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecInt16Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetInt32ArrayLength: - node.setCanExit(!isInt32ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecInt32Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetUint8ArrayLength: - node.setCanExit(!isUint8ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecUint8Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetUint8ClampedArrayLength: - node.setCanExit(!isUint8ClampedArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecUint8ClampedArray); - forNode(nodeIndex).set(SpecInt32); - break; - case GetUint16ArrayLength: - node.setCanExit(!isUint16ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecUint16Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetUint32ArrayLength: - node.setCanExit(!isUint32ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecUint32Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetFloat32ArrayLength: - node.setCanExit(!isFloat32ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecFloat32Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetFloat64ArrayLength: - node.setCanExit(!isFloat64ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecFloat64Array); - forNode(nodeIndex).set(SpecInt32); - break; - case CheckStructure: case ForwardCheckStructure: { // FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes). @@ -1489,65 +1486,48 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(nodeIndex).clear(); // The result is not a JS value. break; case GetIndexedPropertyStorage: { - ASSERT(m_graph[node.child1()].prediction()); - ASSERT(m_graph[node.child2()].shouldSpeculateInteger()); node.setCanExit(true); // Lies, but this is (almost) always followed by GetByVal, which does exit. So no point in trying to be more precise. - if (m_graph[node.child1()].shouldSpeculateArguments()) { - ASSERT_NOT_REACHED(); - break; - } - if (m_graph[node.child1()].prediction() == SpecString) { + switch (node.arrayMode()) { + case Array::String: forNode(node.child1()).filter(SpecString); - forNode(nodeIndex).clear(); break; - } - - if (m_graph[node.child1()].shouldSpeculateInt8Array()) { + case Array::JSArray: + case Array::JSArrayOutOfBounds: + // This doesn't filter anything meaningful right now. We may want to add + // CFA tracking of array mode speculations, but we don't have that, yet. + forNode(node.child1()).filter(SpecCell); + break; + case Array::Int8Array: forNode(node.child1()).filter(SpecInt8Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateInt16Array()) { + case Array::Int16Array: forNode(node.child1()).filter(SpecInt16Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateInt32Array()) { + case Array::Int32Array: forNode(node.child1()).filter(SpecInt32Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateUint8Array()) { + case Array::Uint8Array: forNode(node.child1()).filter(SpecUint8Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { + case Array::Uint8ClampedArray: forNode(node.child1()).filter(SpecUint8ClampedArray); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateUint16Array()) { + case Array::Uint16Array: forNode(node.child1()).filter(SpecUint16Array); - forNode(nodeIndex).set(SpecOther); break; - } - if (m_graph[node.child1()].shouldSpeculateUint32Array()) { + case Array::Uint32Array: forNode(node.child1()).filter(SpecUint32Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateFloat32Array()) { + case Array::Float32Array: forNode(node.child1()).filter(SpecFloat32Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateFloat64Array()) { + case Array::Float64Array: forNode(node.child1()).filter(SpecFloat64Array); - forNode(nodeIndex).clear(); + break; + default: + ASSERT_NOT_REACHED(); break; } - forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).clear(); break; } diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp index 000e1a938..2f535ba22 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp @@ -145,7 +145,7 @@ public: } // Figure out which variables alias the arguments and nothing else, and are - // used only for GetByVal and GetArgumentsLength accesses. At the same time, + // used only for GetByVal and GetArrayLength accesses. At the same time, // identify uses of CreateArguments that are not consistent with the arguments // being aliased only to variables that satisfy these constraints. for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { @@ -277,34 +277,25 @@ public: } case GetByVal: { - if (!node.prediction() - || !m_graph[node.child1()].prediction() - || !m_graph[node.child2()].prediction()) { + if (node.arrayMode() != Array::Arguments) { observeBadArgumentsUses(node); break; } + + // That's so awful and pretty much impossible since it would + // imply that the arguments were predicted integer, but it's + // good to be defensive and thorough. + observeBadArgumentsUse(node.child2()); + observeProperArgumentsUse(node, node.child1()); + break; + } - if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) - || !m_graph[node.child2()].shouldSpeculateInteger()) { + case GetArrayLength: { + if (node.arrayMode() != Array::Arguments) { observeBadArgumentsUses(node); break; } - - if (m_graph[node.child1()].shouldSpeculateArguments()) { - // If arguments is used as an index, then it's an escaping use. - // That's so awful and pretty much impossible since it would - // imply that the arguments were predicted integer, but it's - // good to be defensive and thorough. - observeBadArgumentsUse(node.child2()); - observeProperArgumentsUse(node, node.child1()); - break; - } - - observeBadArgumentsUses(node); - break; - } - - case GetArgumentsLength: { + observeProperArgumentsUse(node, node.child1()); break; } @@ -496,38 +487,32 @@ public: } case GetByVal: { - if (!node.prediction() - || !m_graph[node.child1()].prediction() - || !m_graph[node.child2()].prediction()) + if (node.arrayMode() != Array::Arguments) break; + + // This can be simplified to GetMyArgumentByVal if we know that + // it satisfies either condition (1) or (2): + // 1) Its first child is a valid ArgumentsAliasingData and the + // InlineCallFrame* is not marked as creating arguments. + // 2) Its first child is CreateArguments and its InlineCallFrame* + // is not marked as creating arguments. - if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) - || !m_graph[node.child2()].shouldSpeculateInteger()) + if (!isOKToOptimize(m_graph[node.child1()])) break; - if (m_graph[node.child1()].shouldSpeculateArguments()) { - // This can be simplified to GetMyArgumentByVal if we know that - // it satisfies either condition (1) or (2): - // 1) Its first child is a valid ArgumentsAliasingData and the - // InlineCallFrame* is not marked as creating arguments. - // 2) Its first child is CreateArguments and its InlineCallFrame* - // is not marked as creating arguments. - - if (!isOKToOptimize(m_graph[node.child1()])) - break; - - m_graph.deref(node.child1()); - node.children.child1() = node.children.child2(); - node.children.child2() = Edge(); - node.setOpAndDefaultFlags(GetMyArgumentByVal); - changed = true; - --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal. - break; - } + m_graph.deref(node.child1()); + node.children.child1() = node.children.child2(); + node.children.child2() = Edge(); + node.setOpAndDefaultFlags(GetMyArgumentByVal); + changed = true; + --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal. break; } - case GetArgumentsLength: { + case GetArrayLength: { + if (node.arrayMode() != Array::Arguments) + break; + if (!isOKToOptimize(m_graph[node.child1()])) break; diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp new file mode 100644 index 000000000..ec4edc2e8 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2012 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 "DFGArrayMode.h" + +#if ENABLE(DFG_JIT) + +#include "DFGAbstractValue.h" + +namespace JSC { namespace DFG { + +Array::Mode fromObserved(ArrayModes modes, bool makeSafe) +{ + // FIXME: we may want to add some polymorphic support in the future. That's why this + // is a switch statement right now. + + switch (modes) { + case 0: + return Array::Undecided; + case IsJSArray: + return makeSafe ? Array::JSArrayOutOfBounds : Array::JSArray; + default: + // We know that this is possibly a kind of array for which, though there is no + // useful data in the array profile, we may be able to extract useful data from + // the value profiles of the inputs. Hence, we leave it as undecided, and let + // the predictions propagator decide later. + return Array::Undecided; + } +} + +Array::Mode refineArrayMode(Array::Mode arrayMode, SpeculatedType base, SpeculatedType index) +{ + if (!base || !index) { + // It can be that we had a legitimate arrayMode but no incoming predictions. That'll + // happen if we inlined code based on, say, a global variable watchpoint, but later + // realized that the callsite could not have possibly executed. It may be worthwhile + // to fix that, but for now I'm leaving it as-is. + return Array::ForceExit; + } + + if (!isInt32Speculation(index) || !isCellSpeculation(base)) + return Array::Generic; + + // Pass through any array modes that would have been decided by the array profile, since + // the predictions of the inputs will not tell us anything useful that we didn't already + // get from the array profile. + switch (arrayMode) { + case Array::ForceExit: + case Array::JSArray: + case Array::JSArrayOutOfBounds: + return arrayMode; + default: + break; + } + + if (isStringSpeculation(base)) + return Array::String; + + if (isArgumentsSpeculation(base)) + return Array::Arguments; + + if (isInt8ArraySpeculation(base)) + return Array::Int8Array; + + if (isInt16ArraySpeculation(base)) + return Array::Int16Array; + + if (isInt32ArraySpeculation(base)) + return Array::Int32Array; + + if (isUint8ArraySpeculation(base)) + return Array::Uint8Array; + + if (isUint8ClampedArraySpeculation(base)) + return Array::Uint8ClampedArray; + + if (isUint16ArraySpeculation(base)) + return Array::Uint16Array; + + if (isUint32ArraySpeculation(base)) + return Array::Uint32Array; + + if (isFloat32ArraySpeculation(base)) + return Array::Float32Array; + + if (isFloat64ArraySpeculation(base)) + return Array::Float64Array; + + return Array::Generic; +} + +bool modeAlreadyChecked(AbstractValue& value, Array::Mode arrayMode) +{ + switch (arrayMode) { + case Array::Generic: + return true; + + case Array::ForceExit: + return false; + + case Array::String: + return isStringSpeculation(value.m_type); + + case Array::JSArray: + case Array::JSArrayOutOfBounds: + return value.m_currentKnownStructure.hasSingleton() + && value.m_currentKnownStructure.singleton()->classInfo() == &JSArray::s_info; + + case Array::Arguments: + return isArgumentsSpeculation(value.m_type); + + case Array::Int8Array: + return isInt8ArraySpeculation(value.m_type); + + case Array::Int16Array: + return isInt16ArraySpeculation(value.m_type); + + case Array::Int32Array: + return isInt32ArraySpeculation(value.m_type); + + case Array::Uint8Array: + return isUint8ArraySpeculation(value.m_type); + + case Array::Uint8ClampedArray: + return isUint8ClampedArraySpeculation(value.m_type); + + case Array::Uint16Array: + return isUint16ArraySpeculation(value.m_type); + + case Array::Uint32Array: + return isUint32ArraySpeculation(value.m_type); + + case Array::Float32Array: + return isFloat32ArraySpeculation(value.m_type); + + case Array::Float64Array: + return isFloat64ArraySpeculation(value.m_type); + + case Array::Undecided: + break; + } + + ASSERT_NOT_REACHED(); + return false; +} + +const char* modeToString(Array::Mode mode) +{ + switch (mode) { + case Array::Undecided: + return "Undecided"; + case Array::Generic: + return "Generic"; + case Array::ForceExit: + return "ForceExit"; + case Array::String: + return "String"; + case Array::JSArray: + return "JSArray"; + case Array::JSArrayOutOfBounds: + return "JSArrayOutOfBounds"; + case Array::Arguments: + return "Arguments"; + case Array::Int8Array: + return "Int8Array"; + case Array::Int16Array: + return "Int16Array"; + case Array::Int32Array: + return "Int32Array"; + case Array::Uint8Array: + return "Uint8Array"; + case Array::Uint8ClampedArray: + return "Uint8ClampedArray"; + case Array::Uint16Array: + return "Uint16Array"; + case Array::Uint32Array: + return "Uint32Array"; + case Array::Float32Array: + return "Float32Array"; + case Array::Float64Array: + return "Float64Array"; + default: + // Better to return something then it is to crash. Remember, this method + // is being called from our main diagnostic tool, the IR dumper. It's like + // a stack trace. So if we get here then probably something has already + // gone wrong. + return "Unknown!"; + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h new file mode 100644 index 000000000..6ce62ae72 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012 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 DFGArrayMode_h +#define DFGArrayMode_h + +#include <wtf/Platform.h> + +#if ENABLE(DFG_JIT) + +#include "ArrayProfile.h" +#include "SpeculatedType.h" + +namespace JSC { namespace DFG { + +struct AbstractValue; + +// Use a namespace + enum instead of enum alone to avoid the namespace collision +// that would otherwise occur, since we say things like "Int8Array" and "JSArray" +// in lots of other places, to mean subtly different things. +namespace Array { +enum Mode { + Undecided, // Implies that we need predictions to decide. We will never get to the backend in this mode. + ForceExit, // Implies that we have no idea how to execute this operation, so we should just give up. + Generic, + String, + JSArray, + JSArrayOutOfBounds, + Arguments, + Int8Array, + Int16Array, + Int32Array, + Uint8Array, + Uint8ClampedArray, + Uint16Array, + Uint32Array, + Float32Array, + Float64Array +}; +} // namespace Array + +Array::Mode fromObserved(ArrayModes modes, bool makeSafe); + +Array::Mode refineArrayMode(Array::Mode, SpeculatedType base, SpeculatedType index); + +bool modeAlreadyChecked(AbstractValue&, Array::Mode); + +const char* modeToString(Array::Mode); + +inline bool canCSEStorage(Array::Mode arrayMode) +{ + switch (arrayMode) { + case Array::Undecided: + case Array::ForceExit: + case Array::Generic: + case Array::Arguments: + return false; + default: + return true; + } +} + +inline Array::Mode modeForPut(Array::Mode arrayMode) +{ + switch (arrayMode) { + case Array::String: + return Array::Generic; +#if USE(JSVALUE32_64) + case Array::Arguments: + return Array::Generic; +#endif + default: + return arrayMode; + } +} + +inline bool modesCompatibleForStorageLoad(Array::Mode left, Array::Mode right) +{ + if (left == right) + return true; + + bool leftIsJSArray = + left == Array::JSArray + || left == Array::JSArrayOutOfBounds; + + bool rightIsJSArray = + right == Array::JSArray + || right == Array::JSArrayOutOfBounds; + + if (leftIsJSArray && rightIsJSArray) + return true; + + return false; +} + +inline bool modeSupportsLength(Array::Mode mode) +{ + switch (mode) { + case Array::Undecided: + case Array::ForceExit: + case Array::Generic: + return false; + default: + return true; + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGArrayMode_h + diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index f7536f87f..f9b1db9ab 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -31,6 +31,7 @@ #include "ArrayConstructor.h" #include "CallLinkStatus.h" #include "CodeBlock.h" +#include "DFGArrayMode.h" #include "DFGByteCodeCache.h" #include "DFGCapabilities.h" #include "GetByIdStatus.h" @@ -816,6 +817,36 @@ private: { return getPrediction(m_graph.size(), m_currentProfilingIndex); } + + Array::Mode getArrayModeWithoutOSRExit(Instruction* currentInstruction, NodeIndex base) + { + ArrayProfile* profile = currentInstruction[4].u.arrayProfile; + profile->computeUpdatedPrediction(); + if (profile->hasDefiniteStructure()) + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base); + +#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) + if (m_inlineStackTop->m_profiledBlock->numberOfRareCaseProfiles()) + dataLog("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter); + dataLog("Array profile for bc#%u: %p%s, %u\n", m_currentIndex, profile->expectedStructure(), profile->structureIsPolymorphic() ? " (polymorphic)" : "", profile->observedArrayModes()); +#endif + + bool makeSafe = + m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) + || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, OutOfBounds); + + return fromObserved(profile->observedArrayModes(), makeSafe); + } + + Array::Mode getArrayMode(Instruction* currentInstruction, NodeIndex base) + { + Array::Mode result = getArrayModeWithoutOSRExit(currentInstruction, base); + + if (result == Array::ForceExit) + addToGraph(ForceOSRExit); + + return result; + } NodeIndex makeSafe(NodeIndex nodeIndex) { @@ -1548,8 +1579,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; int indexOperand = registerOffset + argumentToOperand(1); - NodeIndex storage = addToGraph(GetIndexedPropertyStorage, get(thisOperand), getToInt32(indexOperand)); - NodeIndex charCode = addToGraph(StringCharCodeAt, get(thisOperand), getToInt32(indexOperand), storage); + NodeIndex charCode = addToGraph(StringCharCodeAt, OpInfo(Array::String), get(thisOperand), getToInt32(indexOperand)); if (usesResult) set(resultOperand, charCode); @@ -1565,8 +1595,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; int indexOperand = registerOffset + argumentToOperand(1); - NodeIndex storage = addToGraph(GetIndexedPropertyStorage, get(thisOperand), getToInt32(indexOperand)); - NodeIndex charCode = addToGraph(StringCharAt, get(thisOperand), getToInt32(indexOperand), storage); + NodeIndex charCode = addToGraph(StringCharAt, OpInfo(Array::String), get(thisOperand), getToInt32(indexOperand)); if (usesResult) set(resultOperand, charCode); @@ -2148,13 +2177,9 @@ bool ByteCodeParser::parseBlock(unsigned limit) SpeculatedType prediction = getPrediction(); NodeIndex base = get(currentInstruction[2].u.operand); + Array::Mode arrayMode = getArrayMode(currentInstruction, base); NodeIndex property = get(currentInstruction[3].u.operand); - ArrayProfile* profile = currentInstruction[4].u.arrayProfile; - profile->computeUpdatedPrediction(); - if (profile->hasDefiniteStructure()) - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base); - NodeIndex propertyStorage = addToGraph(GetIndexedPropertyStorage, base, property); - NodeIndex getByVal = addToGraph(GetByVal, OpInfo(0), OpInfo(prediction), base, property, propertyStorage); + NodeIndex getByVal = addToGraph(GetByVal, OpInfo(arrayMode), OpInfo(prediction), base, property); set(currentInstruction[1].u.operand, getByVal); NEXT_OPCODE(op_get_by_val); @@ -2162,26 +2187,16 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_put_by_val: { NodeIndex base = get(currentInstruction[1].u.operand); + + Array::Mode arrayMode = getArrayMode(currentInstruction, base); + NodeIndex property = get(currentInstruction[2].u.operand); NodeIndex value = get(currentInstruction[3].u.operand); - ArrayProfile* profile = currentInstruction[4].u.arrayProfile; - profile->computeUpdatedPrediction(); - if (profile->hasDefiniteStructure()) - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base); - -#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter); -#endif - - bool makeSafe = - m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) - || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, OutOfBounds); - addVarArgChild(base); addVarArgChild(property); addVarArgChild(value); - addToGraph(Node::VarArg, makeSafe ? PutByValSafe : PutByVal, OpInfo(0), OpInfo(0)); + addToGraph(Node::VarArg, PutByVal, OpInfo(arrayMode), OpInfo(0)); NEXT_OPCODE(op_put_by_val); } diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp index b78ddc89d..dce57d520 100644 --- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp @@ -284,8 +284,7 @@ private: return index; break; case PutByVal: - case PutByValAlias: - case PutByValSafe: { + case PutByValAlias: { if (!m_graph.byValIsPure(node)) return NoNode; if (m_graph.varArgChild(node, 0) == child1 && canonicalize(m_graph.varArgChild(node, 1)) == canonicalize(child2)) @@ -365,7 +364,6 @@ private: case PutByVal: case PutByValAlias: - case PutByValSafe: if (m_graph.byValIsPure(node)) { // If PutByVal speculates that it's accessing an array with an // integer index, then it's impossible for it to cause a structure @@ -409,7 +407,6 @@ private: case PutByVal: case PutByValAlias: - case PutByValSafe: if (m_graph.byValIsPure(node)) { // If PutByVal speculates that it's accessing an array with an // integer index, then it's impossible for it to cause a structure @@ -515,7 +512,6 @@ private: case PutByVal: case PutByValAlias: - case PutByValSafe: if (m_graph.byValIsPure(node)) { // If PutByVal speculates that it's accessing an array with an // integer index, then it's impossible for it to cause a structure @@ -560,7 +556,6 @@ private: case PutByVal: case PutByValAlias: case GetByVal: - case PutByValSafe: if (m_graph.byValIsPure(node)) { // If PutByVal speculates that it's accessing an array with an // integer index, then it's impossible for it to cause a structure @@ -613,7 +608,6 @@ private: case PutByVal: case PutByValAlias: - case PutByValSafe: if (m_graph.byValIsPure(node)) { // If PutByVal speculates that it's accessing an array with an // integer index, then it's impossible for it to cause a structure @@ -925,17 +919,7 @@ private: case ArithMin: case ArithMax: case ArithSqrt: - case GetInt8ArrayLength: - case GetInt16ArrayLength: - case GetInt32ArrayLength: - case GetUint8ArrayLength: - case GetUint8ClampedArrayLength: - case GetUint16ArrayLength: - case GetUint32ArrayLength: - case GetFloat32ArrayLength: - case GetFloat64ArrayLength: case GetCallee: - case GetStringLength: case StringCharAt: case StringCharCodeAt: case Int32ToDouble: @@ -1103,8 +1087,7 @@ private: setReplacement(getByValLoadElimination(node.child1().index(), node.child2().index())); break; - case PutByVal: - case PutByValSafe: { + case PutByVal: { Edge child1 = m_graph.varArgChild(node, 0); Edge child2 = m_graph.varArgChild(node, 1); if (isActionableMutableArraySpeculation(m_graph[child1].prediction()) diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp index f7b10fc43..fe7cae8a9 100644 --- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp @@ -74,97 +74,89 @@ private: switch (op) { case GetById: { + Node* nodePtr = &node; + if (!isInt32Speculation(m_graph[m_compileIndex].prediction())) break; - if (codeBlock()->identifier(node.identifierNumber()) != globalData().propertyNames->length) - break; - bool isArray = isArraySpeculation(m_graph[node.child1()].prediction()); - bool isArguments = isArgumentsSpeculation(m_graph[node.child1()].prediction()); - bool isString = isStringSpeculation(m_graph[node.child1()].prediction()); - bool isInt8Array = m_graph[node.child1()].shouldSpeculateInt8Array(); - bool isInt16Array = m_graph[node.child1()].shouldSpeculateInt16Array(); - bool isInt32Array = m_graph[node.child1()].shouldSpeculateInt32Array(); - bool isUint8Array = m_graph[node.child1()].shouldSpeculateUint8Array(); - bool isUint8ClampedArray = m_graph[node.child1()].shouldSpeculateUint8ClampedArray(); - bool isUint16Array = m_graph[node.child1()].shouldSpeculateUint16Array(); - bool isUint32Array = m_graph[node.child1()].shouldSpeculateUint32Array(); - bool isFloat32Array = m_graph[node.child1()].shouldSpeculateFloat32Array(); - bool isFloat64Array = m_graph[node.child1()].shouldSpeculateFloat64Array(); - if (!isArray && !isArguments && !isString && !isInt8Array && !isInt16Array && !isInt32Array && !isUint8Array && !isUint8ClampedArray && !isUint16Array && !isUint32Array && !isFloat32Array && !isFloat64Array) + if (codeBlock()->identifier(nodePtr->identifierNumber()) != globalData().propertyNames->length) break; - -#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog(" @%u -> %s", m_compileIndex, isArray ? "GetArrayLength" : "GetStringLength"); -#endif - if (isArray) { - node.setOp(GetArrayLength); - ASSERT(node.flags() & NodeMustGenerate); - node.clearFlags(NodeMustGenerate); - m_graph.deref(m_compileIndex); - - ArrayProfile* arrayProfile = - m_graph.baselineCodeBlockFor(node.codeOrigin)->getArrayProfile( - node.codeOrigin.bytecodeIndex); - if (!arrayProfile) - break; + ArrayProfile* arrayProfile = + m_graph.baselineCodeBlockFor(nodePtr->codeOrigin)->getArrayProfile( + nodePtr->codeOrigin.bytecodeIndex); + Array::Mode arrayMode = Array::Undecided; + if (arrayProfile) { arrayProfile->computeUpdatedPrediction(); - if (!arrayProfile->hasDefiniteStructure()) - break; - m_graph.ref(node.child1()); - Node checkStructure(CheckStructure, node.codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())), node.child1().index()); - checkStructure.ref(); - NodeIndex checkStructureIndex = m_graph.size(); - m_graph.append(checkStructure); - m_insertionSet.append(m_indexInBlock, checkStructureIndex); - break; + arrayMode = refineArrayMode( + fromObserved(arrayProfile->observedArrayModes(), false), + m_graph[node.child1()].prediction(), + m_graph[m_compileIndex].prediction()); + if (modeSupportsLength(arrayMode) + && arrayProfile->hasDefiniteStructure()) { + m_graph.ref(nodePtr->child1()); + Node checkStructure(CheckStructure, nodePtr->codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())), nodePtr->child1().index()); + checkStructure.ref(); + NodeIndex checkStructureIndex = m_graph.size(); + m_graph.append(checkStructure); + m_insertionSet.append(m_indexInBlock, checkStructureIndex); + nodePtr = &m_graph[m_compileIndex]; + } + } else { + arrayMode = refineArrayMode( + arrayMode, + m_graph[node.child1()].prediction(), + m_graph[m_compileIndex].prediction()); } - if (isArguments) - node.setOp(GetArgumentsLength); - else if (isString) - node.setOp(GetStringLength); - else if (isInt8Array) - node.setOp(GetInt8ArrayLength); - else if (isInt16Array) - node.setOp(GetInt16ArrayLength); - else if (isInt32Array) - node.setOp(GetInt32ArrayLength); - else if (isUint8Array) - node.setOp(GetUint8ArrayLength); - else if (isUint8ClampedArray) - node.setOp(GetUint8ClampedArrayLength); - else if (isUint16Array) - node.setOp(GetUint16ArrayLength); - else if (isUint32Array) - node.setOp(GetUint32ArrayLength); - else if (isFloat32Array) - node.setOp(GetFloat32ArrayLength); - else if (isFloat64Array) - node.setOp(GetFloat64ArrayLength); - else - ASSERT_NOT_REACHED(); - // No longer MustGenerate - ASSERT(node.flags() & NodeMustGenerate); - node.clearFlags(NodeMustGenerate); + if (!modeSupportsLength(arrayMode)) + break; + nodePtr->setOp(GetArrayLength); + ASSERT(nodePtr->flags() & NodeMustGenerate); + nodePtr->clearFlags(NodeMustGenerate); m_graph.deref(m_compileIndex); + nodePtr->setArrayMode(arrayMode); break; } case GetIndexedPropertyStorage: { - if (!m_graph[node.child1()].prediction() - || !m_graph[node.child2()].shouldSpeculateInteger() - || m_graph[node.child1()].shouldSpeculateArguments()) { - node.setOpAndDefaultFlags(Nop); - m_graph.clearAndDerefChild1(node); - m_graph.clearAndDerefChild2(node); - m_graph.clearAndDerefChild3(node); - node.setRefCount(0); - } + node.setArrayMode( + refineArrayMode( + node.arrayMode(), + m_graph[node.child1()].prediction(), + m_graph[node.child2()].prediction())); + // Predictions should only become more, rather than less, refined. Hence + // if we were ever able to CSE the storage pointer for this operation, + // then we should always continue to be able to do so. + ASSERT(canCSEStorage(node.arrayMode())); break; } case GetByVal: case StringCharAt: case StringCharCodeAt: { - if (!!node.child3() && m_graph[node.child3()].op() == Nop) - node.children.child3() = Edge(); + node.setArrayMode( + refineArrayMode( + node.arrayMode(), + m_graph[node.child1()].prediction(), + m_graph[node.child2()].prediction())); + + if (canCSEStorage(node.arrayMode())) { + if (node.child3()) { + ASSERT(m_graph[node.child3()].op() == GetIndexedPropertyStorage); + ASSERT(modesCompatibleForStorageLoad(m_graph[node.child3()].arrayMode(), node.arrayMode())); + } else { + // Make sure we don't use the node reference after we do the append. + Node getIndexedPropertyStorage( + GetIndexedPropertyStorage, node.codeOrigin, OpInfo(node.arrayMode()), + node.child1().index(), node.child2().index()); + NodeIndex getIndexedPropertyStorageIndex = m_graph.size(); + node.children.child3() = Edge(getIndexedPropertyStorageIndex); + m_graph.append(getIndexedPropertyStorage); + m_graph.ref(getIndexedPropertyStorageIndex); // Once because it's MustGenerate. + m_graph.ref(getIndexedPropertyStorageIndex); // And again because it's referenced from the GetByVal. + m_insertionSet.append(m_indexInBlock, getIndexedPropertyStorageIndex); + } + } else { + // See above. Continued fixup of the graph should not regress our ability + // to speculate. + ASSERT(!node.child3()); + } break; } @@ -334,24 +326,30 @@ private: } case PutByVal: - case PutByValSafe: { + case PutByValAlias: { Edge child1 = m_graph.varArgChild(node, 0); Edge child2 = m_graph.varArgChild(node, 1); Edge child3 = m_graph.varArgChild(node, 2); - if (!m_graph[child1].prediction() || !m_graph[child2].prediction()) - break; - if (!m_graph[child2].shouldSpeculateInteger()) + node.setArrayMode( + refineArrayMode( + node.arrayMode(), m_graph[child1].prediction(), m_graph[child2].prediction())); + + switch (modeForPut(node.arrayMode())) { + case Array::Int8Array: + case Array::Int16Array: + case Array::Int32Array: + case Array::Uint8Array: + case Array::Uint8ClampedArray: + case Array::Uint16Array: + case Array::Uint32Array: + if (!m_graph[child3].shouldSpeculateInteger()) + fixDoubleEdge(2); break; - if (isActionableIntMutableArraySpeculation(m_graph[child1].prediction())) { - if (m_graph[child3].isConstant()) - break; - if (m_graph[child3].shouldSpeculateInteger()) - break; + case Array::Float32Array: + case Array::Float64Array: fixDoubleEdge(2); break; - } - if (isActionableFloatMutableArraySpeculation(m_graph[child1].prediction())) { - fixDoubleEdge(2); + default: break; } break; diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp index 9ae0648b8..8e80ff2fc 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.cpp +++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp @@ -211,6 +211,10 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex) dataLog("%s%s", hasPrinted ? ", " : "", nodeFlagsAsString(node.flags())); hasPrinted = true; } + if (node.hasArrayMode()) { + dataLog("%s%s", hasPrinted ? ", " : "", modeToString(node.arrayMode())); + hasPrinted = true; + } if (node.hasVarNumber()) { dataLog("%svar%u", hasPrinted ? ", " : "", node.varNumber()); hasPrinted = true; diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index 8d164a299..ba5d86f81 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -488,48 +488,20 @@ public: bool byValIsPure(Node& node) { - switch (node.op()) { - case PutByVal: { - if (!at(varArgChild(node, 1)).shouldSpeculateInteger()) - return false; - SpeculatedType prediction = at(varArgChild(node, 0)).prediction(); - if (!isActionableMutableArraySpeculation(prediction)) - return false; - return true; - } - - case PutByValSafe: { - if (!at(varArgChild(node, 1)).shouldSpeculateInteger()) - return false; - SpeculatedType prediction = at(varArgChild(node, 0)).prediction(); - if (!isActionableMutableArraySpeculation(prediction)) - return false; - if (isArraySpeculation(prediction)) - return false; - return true; - } - - case PutByValAlias: { - if (!at(varArgChild(node, 1)).shouldSpeculateInteger()) - return false; - SpeculatedType prediction = at(varArgChild(node, 0)).prediction(); - if (!isActionableMutableArraySpeculation(prediction)) - return false; - return true; - } - - case GetByVal: { - if (!at(node.child2()).shouldSpeculateInteger()) - return false; - SpeculatedType prediction = at(node.child1()).prediction(); - if (!isActionableArraySpeculation(prediction)) - return false; - return true; - } - - default: - ASSERT_NOT_REACHED(); + switch (node.arrayMode()) { + case Array::Generic: + case Array::JSArrayOutOfBounds: return false; + case Array::String: + return node.op() == GetByVal; +#if USE(JSVALUE32_64) + case Array::Arguments: + if (node.op() == GetByVal) + return true; + return false; +#endif // USE(JSVALUE32_64) + default: + return true; } } @@ -549,7 +521,6 @@ public: return !isPredictedNumerical(node); case GetByVal: case PutByVal: - case PutByValSafe: case PutByValAlias: return !byValIsPure(node); default: diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index dac855be0..7ca4d8d48 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -33,6 +33,7 @@ #include "CodeBlock.h" #include "CodeOrigin.h" #include "DFGAdjacencyList.h" +#include "DFGArrayMode.h" #include "DFGCommon.h" #include "DFGNodeFlags.h" #include "DFGNodeType.h" @@ -732,6 +733,34 @@ struct Node { return m_opInfo; } + bool hasArrayMode() + { + switch (op()) { + case GetIndexedPropertyStorage: + case GetArrayLength: + case PutByVal: + case PutByValAlias: + case GetByVal: + case StringCharAt: + case StringCharCodeAt: + return true; + default: + return false; + } + } + + Array::Mode arrayMode() + { + ASSERT(hasArrayMode()); + return static_cast<Array::Mode>(m_opInfo); + } + + void setArrayMode(Array::Mode arrayMode) + { + ASSERT(hasArrayMode()); + m_opInfo = arrayMode; + } + bool hasVirtualRegister() { return m_virtualRegister != InvalidVirtualRegister; diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h index f0f8cb1d0..ee5ad9013 100644 --- a/Source/JavaScriptCore/dfg/DFGNodeType.h +++ b/Source/JavaScriptCore/dfg/DFGNodeType.h @@ -113,7 +113,6 @@ namespace JSC { namespace DFG { /* opcodes use VarArgs beause they may have up to 4 children. */\ macro(GetByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \ macro(PutByVal, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \ - macro(PutByValSafe, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \ macro(PutByValAlias, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \ macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ macro(GetByIdFlush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ @@ -143,17 +142,6 @@ namespace JSC { namespace DFG { macro(GetByOffset, NodeResultJS) \ macro(PutByOffset, NodeMustGenerate) \ macro(GetArrayLength, NodeResultInt32) \ - macro(GetArgumentsLength, NodeResultInt32) \ - macro(GetStringLength, NodeResultInt32) \ - macro(GetInt8ArrayLength, NodeResultInt32) \ - macro(GetInt16ArrayLength, NodeResultInt32) \ - macro(GetInt32ArrayLength, NodeResultInt32) \ - macro(GetUint8ArrayLength, NodeResultInt32) \ - macro(GetUint8ClampedArrayLength, NodeResultInt32) \ - macro(GetUint16ArrayLength, NodeResultInt32) \ - macro(GetUint32ArrayLength, NodeResultInt32) \ - macro(GetFloat32ArrayLength, NodeResultInt32) \ - macro(GetFloat64ArrayLength, NodeResultInt32) \ macro(GetScopeChain, NodeResultJS) \ macro(GetScopedVar, NodeResultJS | NodeMustGenerate) \ macro(PutScopedVar, NodeMustGenerate | NodeClobbersWorld) \ diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index 1247528e8..258d1199a 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -612,17 +612,6 @@ private: case PutByValAlias: case GetArrayLength: - case GetArgumentsLength: - case GetInt8ArrayLength: - case GetInt16ArrayLength: - case GetInt32ArrayLength: - case GetUint8ArrayLength: - case GetUint8ClampedArrayLength: - case GetUint16ArrayLength: - case GetUint32ArrayLength: - case GetFloat32ArrayLength: - case GetFloat64ArrayLength: - case GetStringLength: case Int32ToDouble: case DoubleAsInt32: case GetLocalUnlinked: @@ -637,7 +626,6 @@ private: } case PutByVal: - case PutByValSafe: changed |= m_graph[m_graph.varArgChild(node, 0)].mergeFlags(NodeUsedAsValue); changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); changed |= m_graph[m_graph.varArgChild(node, 2)].mergeFlags(NodeUsedAsValue); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 6c6615716..d74207420 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -269,12 +269,82 @@ void SpeculativeJIT::clearGenerationInfo() m_fprs = RegisterBank<FPRInfo>(); } -void SpeculativeJIT::speculateArray(Edge edge, GPRReg baseReg) +const TypedArrayDescriptor* SpeculativeJIT::typedArrayDescriptor(Array::Mode arrayMode) +{ + switch (arrayMode) { + case Array::Int8Array: + return &m_jit.globalData()->int8ArrayDescriptor(); + case Array::Int16Array: + return &m_jit.globalData()->int16ArrayDescriptor(); + case Array::Int32Array: + return &m_jit.globalData()->int32ArrayDescriptor(); + case Array::Uint8Array: + return &m_jit.globalData()->uint8ArrayDescriptor(); + case Array::Uint8ClampedArray: + return &m_jit.globalData()->uint8ClampedArrayDescriptor(); + case Array::Uint16Array: + return &m_jit.globalData()->uint16ArrayDescriptor(); + case Array::Uint32Array: + return &m_jit.globalData()->uint32ArrayDescriptor(); + case Array::Float32Array: + return &m_jit.globalData()->float32ArrayDescriptor(); + case Array::Float64Array: + return &m_jit.globalData()->float32ArrayDescriptor(); + default: + return 0; + } +} + +const TypedArrayDescriptor* SpeculativeJIT::speculateArray(Array::Mode arrayMode, Edge edge, GPRReg baseReg) { - AbstractValue& arrayValue = m_state.forNode(edge); - if (arrayValue.m_currentKnownStructure.hasSingleton() - && arrayValue.m_currentKnownStructure.singleton()->classInfo() == &JSArray::s_info) - return; + const TypedArrayDescriptor* result = typedArrayDescriptor(arrayMode); + + if (modeAlreadyChecked(m_state.forNode(edge), arrayMode)) + return result; + + const ClassInfo* expectedClassInfo = 0; + + switch (arrayMode) { + case Array::ForceExit: + ASSERT_NOT_REACHED(); + terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); + return result; + case Array::String: + expectedClassInfo = &JSString::s_info; + break; + case Array::JSArray: + case Array::JSArrayOutOfBounds: { + // This code duplicates the code below in anticipation of this code being + // substantially changed in the future. + GPRTemporary temp(this); + m_jit.loadPtr( + MacroAssembler::Address(baseReg, JSCell::structureOffset()), temp.gpr()); + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branchPtr( + MacroAssembler::NotEqual, + MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()), + MacroAssembler::TrustedImmPtr(&JSArray::s_info))); + return result; + } + case Array::Arguments: + expectedClassInfo = &Arguments::s_info; + break; + case Array::Int8Array: + case Array::Int16Array: + case Array::Int32Array: + case Array::Uint8Array: + case Array::Uint8ClampedArray: + case Array::Uint16Array: + case Array::Uint32Array: + case Array::Float32Array: + case Array::Float64Array: + expectedClassInfo = result->m_classInfo; + break; + default: + ASSERT_NOT_REACHED(); + break; + } GPRTemporary temp(this); m_jit.loadPtr( @@ -284,7 +354,9 @@ void SpeculativeJIT::speculateArray(Edge edge, GPRReg baseReg) m_jit.branchPtr( MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()), - MacroAssembler::TrustedImmPtr(&JSArray::s_info))); + MacroAssembler::TrustedImmPtr(expectedClassInfo))); + + return result; } GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex) @@ -1620,11 +1692,7 @@ void SpeculativeJIT::compileGetByValOnString(Node& node) GPRReg propertyReg = property.gpr(); GPRReg storageReg = storage.gpr(); - if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); - noResult(m_compileIndex); - return; - } + ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), Array::String)); // unsigned comparison so we can filter out negative indices and indices that are too large speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSString::offsetOfLength()))); @@ -2018,23 +2086,7 @@ static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg sou } -void SpeculativeJIT::compileGetTypedArrayLength(const TypedArrayDescriptor& descriptor, Node& node, bool needsSpeculationCheck) -{ - SpeculateCellOperand base(this, node.child1()); - GPRTemporary result(this); - - GPRReg baseGPR = base.gpr(); - GPRReg resultGPR = result.gpr(); - - if (needsSpeculationCheck) - speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - - m_jit.load32(MacroAssembler::Address(baseGPR, descriptor.m_lengthOffset), resultGPR); - - integerResult(resultGPR, m_compileIndex); -} - -void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements, TypedArraySignedness signedness) +void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize, TypedArraySignedness signedness) { SpeculateCellOperand base(this, node.child1()); SpeculateStrictInt32Operand property(this, node.child2()); @@ -2047,12 +2099,7 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& GPRTemporary result(this); GPRReg resultReg = result.gpr(); - if (speculationRequirements != NoTypedArrayTypeSpecCheck) { - ASSERT_NOT_REACHED(); - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); - noResult(m_compileIndex); - return; - } + ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode())); speculationCheck( Uncountable, JSValueRegs(), NoNode, @@ -2097,13 +2144,10 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& doubleResult(fresult.fpr(), m_compileIndex); } -void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements, TypedArraySignedness signedness, TypedArrayRounding rounding) +void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySignedness signedness, TypedArrayRounding rounding) { - Edge baseUse = m_jit.graph().varArgChild(node, 0); Edge valueUse = m_jit.graph().varArgChild(node, 2); - if (speculationRequirements != NoTypedArrayTypeSpecCheck) - speculationCheck(BadType, JSValueSource::unboxedCell(base), baseUse, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(base, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); GPRTemporary value; GPRReg valueGPR; @@ -2174,7 +2218,7 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& ASSERT(valueGPR != storageReg); m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg); MacroAssembler::Jump outOfBounds; - if (speculationRequirements != NoTypedArraySpecCheck) + if (node.op() == PutByVal) outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset)); switch (elementSize) { @@ -2190,12 +2234,12 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& default: ASSERT_NOT_REACHED(); } - if (speculationRequirements != NoTypedArraySpecCheck) + if (node.op() == PutByVal) outOfBounds.link(&m_jit); noResult(m_compileIndex); } -void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements) +void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize) { SpeculateCellOperand base(this, node.child1()); SpeculateStrictInt32Operand property(this, node.child2()); @@ -2204,17 +2248,11 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor GPRReg baseReg = base.gpr(); GPRReg propertyReg = property.gpr(); GPRReg storageReg = storage.gpr(); - - if (speculationRequirements != NoTypedArrayTypeSpecCheck) { - ASSERT_NOT_REACHED(); - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); - noResult(m_compileIndex); - return; - } + + ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode())); FPRTemporary result(this); FPRReg resultReg = result.fpr(); - ASSERT(speculationRequirements != NoTypedArraySpecCheck); speculationCheck( Uncountable, JSValueRegs(), NoNode, m_jit.branch32( @@ -2238,15 +2276,14 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor doubleResult(resultReg, m_compileIndex); } -void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements) +void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize) { Edge baseUse = m_jit.graph().varArgChild(node, 0); Edge valueUse = m_jit.graph().varArgChild(node, 2); SpeculateDoubleOperand valueOp(this, valueUse); - if (speculationRequirements != NoTypedArrayTypeSpecCheck) - speculationCheck(BadType, JSValueSource::unboxedCell(base), baseUse.index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(base, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); + ASSERT_UNUSED(baseUse, modeAlreadyChecked(m_state.forNode(baseUse), node.arrayMode())); GPRTemporary result(this); @@ -2255,7 +2292,7 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescripto m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg); MacroAssembler::Jump outOfBounds; - if (speculationRequirements != NoTypedArraySpecCheck) + if (node.op() == PutByVal) outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset)); switch (elementSize) { @@ -2272,7 +2309,7 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescripto default: ASSERT_NOT_REACHED(); } - if (speculationRequirements != NoTypedArraySpecCheck) + if (node.op() == PutByVal) outOfBounds.link(&m_jit); noResult(m_compileIndex); } @@ -3066,75 +3103,36 @@ bool SpeculativeJIT::compileStrictEq(Node& node) void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node) { - ASSERT(at(node.child1()).prediction()); - ASSERT(at(node.child2()).shouldSpeculateInteger()); - SpeculateCellOperand base(this, node.child1()); GPRReg baseReg = base.gpr(); GPRTemporary storage(this); GPRReg storageReg = storage.gpr(); - if (at(node.child1()).shouldSpeculateArguments()) { - ASSERT_NOT_REACHED(); - } else if (at(node.child1()).prediction() == SpecString) { - if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()))); - + + const TypedArrayDescriptor* descriptor = + speculateArray(node.arrayMode(), node.child1(), baseReg); + + switch (node.arrayMode()) { + case Array::String: m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), storageReg); // Speculate that we're not accessing a rope speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, storageReg)); m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg); - } else if (at(node.child1()).shouldSpeculateInt8Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->int8ArrayDescriptor(); - if (!isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateInt16Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->int16ArrayDescriptor(); - if (!isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateInt32Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->int32ArrayDescriptor(); - if (!isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateUint8Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ArrayDescriptor(); - if (!isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ClampedArrayDescriptor(); - if (!isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateUint16Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint16ArrayDescriptor(); - if (!isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateUint32Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint32ArrayDescriptor(); - if (!isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateFloat32Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->float32ArrayDescriptor(); - if (!isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateFloat64Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->float64ArrayDescriptor(); - if (!isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else { - speculateArray(node.child1(), baseReg); + break; + + case Array::JSArray: + case Array::JSArrayOutOfBounds: m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); + break; + + default: + ASSERT(descriptor); + m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor->m_storageOffset), storageReg); + break; } + storageResult(storageReg, m_compileIndex); } @@ -3252,6 +3250,42 @@ void SpeculativeJIT::compileGetArgumentsLength(Node& node) integerResult(resultReg, m_compileIndex); } +void SpeculativeJIT::compileGetArrayLength(Node& node) +{ + SpeculateCellOperand base(this, node.child1()); + GPRTemporary result(this); + + GPRReg baseGPR = base.gpr(); + GPRReg resultGPR = result.gpr(); + + const TypedArrayDescriptor* descriptor = + speculateArray(node.arrayMode(), node.child1(), baseGPR); + + switch (node.arrayMode()) { + case Array::JSArray: + case Array::JSArrayOutOfBounds: + m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR); + m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR); + + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0))); + + integerResult(resultGPR, m_compileIndex); + break; + case Array::String: + m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); + integerResult(resultGPR, m_compileIndex); + break; + case Array::Arguments: + compileGetArgumentsLength(node); + break; + default: + ASSERT(descriptor); + m_jit.load32(MacroAssembler::Address(baseGPR, descriptor->m_lengthOffset), resultGPR); + integerResult(resultGPR, m_compileIndex); + break; + } +} + void SpeculativeJIT::compileNewFunctionNoCheck(Node& node) { GPRResult result(this); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 073dbb42c..69a30a974 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -2082,6 +2082,8 @@ public: void compileGetByValOnArguments(Node&); void compileGetArgumentsLength(Node&); + void compileGetArrayLength(Node&); + void compileValueToInt32(Node&); void compileUInt32ToNumber(Node&); void compileDoubleAsInt32(Node&); @@ -2095,12 +2097,6 @@ public: #endif void compileArithMod(Node&); void compileSoftModulo(Node&); - void compileGetTypedArrayLength(const TypedArrayDescriptor&, Node&, bool needsSpeculationCheck); - enum TypedArraySpeculationRequirements { - NoTypedArraySpecCheck, - NoTypedArrayTypeSpecCheck, - AllTypedArraySpecChecks - }; enum TypedArraySignedness { SignedTypedArray, UnsignedTypedArray @@ -2110,10 +2106,10 @@ public: ClampRounding }; void compileGetIndexedPropertyStorage(Node&); - void compileGetByValOnIntTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness); - void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness, TypedArrayRounding = TruncateRounding); - void compileGetByValOnFloatTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements); - void compilePutByValForFloatTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements); + void compileGetByValOnIntTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySignedness); + void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySignedness, TypedArrayRounding = TruncateRounding); + void compileGetByValOnFloatTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize); + void compilePutByValForFloatTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize); void compileNewFunctionNoCheck(Node&); void compileNewFunctionExpression(Node&); bool compileRegExpExec(Node&); @@ -2199,7 +2195,9 @@ public: JumpReplacementWatchpoint* forwardSpeculationWatchpoint(ExitKind = UncountableWatchpoint); JumpReplacementWatchpoint* speculationWatchpointWithConditionalDirection(ExitKind, bool isForward); - void speculateArray(Edge baseEdge, GPRReg baseReg); + const TypedArrayDescriptor* typedArrayDescriptor(Array::Mode); + + const TypedArrayDescriptor* speculateArray(Array::Mode, Edge baseEdge, GPRReg baseReg); template<bool strict> GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 7a9ba1e41..26a48dcec 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -2341,12 +2341,13 @@ void SpeculativeJIT::compile(Node& node) } case GetByVal: { - if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) { + switch (node.arrayMode()) { + case Array::Undecided: + case Array::ForceExit: + ASSERT_NOT_REACHED(); terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); break; - } - - if (!at(node.child2()).shouldSpeculateInteger() || (!node.child3() && !at(node.child1()).shouldSpeculateArguments())) { + case Array::Generic: { SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right. JSValueOperand property(this, node.child2()); GPRReg baseGPR = base.gpr(); @@ -2361,125 +2362,94 @@ void SpeculativeJIT::compile(Node& node) jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex); break; } + case Array::JSArray: + case Array::JSArrayOutOfBounds: { + SpeculateStrictInt32Operand property(this, node.child2()); + StorageOperand storage(this, node.child3()); + GPRReg propertyReg = property.gpr(); + GPRReg storageReg = storage.gpr(); - if (at(node.child1()).shouldSpeculateArguments()) { - compileGetByValOnArguments(node); if (!m_compileOkay) return; + + // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). + // If we have predicted the base to be type array, we can skip the check. + { + SpeculateCellOperand base(this, node.child1()); + GPRReg baseReg = base.gpr(); + // We've already speculated that it's some kind of array, at this point. + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); + } + + GPRTemporary resultTag(this); + GPRTemporary resultPayload(this); + + m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr()); + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag))); + m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr()); + + jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex); break; } - - if (at(node.child1()).prediction() == SpecString) { + case Array::String: compileGetByValOnString(node); - if (!m_compileOkay) - return; break; - } - - if (at(node.child1()).shouldSpeculateInt8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateInt16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateInt32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; + case Array::Arguments: + compileGetByValOnArguments(node); + break; + case Array::Int8Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), SignedTypedArray); + break; + case Array::Int16Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), SignedTypedArray); + break; + case Array::Int32Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), SignedTypedArray); + break; + case Array::Uint8Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + case Array::Uint8ClampedArray: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + case Array::Uint16Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), UnsignedTypedArray); + break; + case Array::Uint32Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), UnsignedTypedArray); + break; + case Array::Float32Array: + compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float)); + break; + case Array::Float64Array: + compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double)); + break; + default: + ASSERT_NOT_REACHED(); break; } - - if (at(node.child1()).shouldSpeculateUint16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateFloat32Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateFloat64Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - - SpeculateStrictInt32Operand property(this, node.child2()); - StorageOperand storage(this, node.child3()); - GPRReg propertyReg = property.gpr(); - GPRReg storageReg = storage.gpr(); - - if (!m_compileOkay) - return; - - // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). - // If we have predicted the base to be type array, we can skip the check. - { - SpeculateCellOperand base(this, node.child1()); - GPRReg baseReg = base.gpr(); - // We've already speculated that it's some kind of array, at this point. - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); - } - - GPRTemporary resultTag(this); - GPRTemporary resultPayload(this); - - m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr()); - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag))); - m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr()); - - jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex); break; } case PutByVal: - case PutByValSafe: { + case PutByValAlias: { Edge child1 = m_jit.graph().varArgChild(node, 0); Edge child2 = m_jit.graph().varArgChild(node, 1); Edge child3 = m_jit.graph().varArgChild(node, 2); - if (!at(child1).prediction() || !at(child2).prediction()) { + Array::Mode arrayMode = modeForPut(node.arrayMode()); + bool alreadyHandled = false; + + switch (arrayMode) { + case Array::Undecided: + case Array::ForceExit: + ASSERT_NOT_REACHED(); terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); + alreadyHandled = true; break; - } - - if (!at(child2).shouldSpeculateInteger() - || at(child1).shouldSpeculateArguments()) { + case Array::Generic: { + ASSERT(node.op() == PutByVal); + SpeculateCellOperand base(this, child1); // Save a register, speculate cell. We'll probably be right. JSValueOperand property(this, child2); JSValueOperand value(this, child3); @@ -2493,233 +2463,144 @@ void SpeculativeJIT::compile(Node& node) callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValCellStrict : operationPutByValCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR); noResult(m_compileIndex); + alreadyHandled = true; break; } - - SpeculateCellOperand base(this, child1); - SpeculateStrictInt32Operand property(this, child2); - if (at(child1).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); - if (!m_compileOkay) - return; + default: break; } - - if (at(child1).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - if (at(child1).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } + if (alreadyHandled) + break; - if (at(child1).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } + SpeculateCellOperand base(this, child1); + SpeculateStrictInt32Operand property(this, child2); - JSValueOperand value(this, child3); - // Map base, property & value into registers, allocate a scratch register. GPRReg baseReg = base.gpr(); GPRReg propertyReg = property.gpr(); - GPRReg valueTagReg = value.tagGPR(); - GPRReg valuePayloadReg = value.payloadGPR(); - - if (!m_compileOkay) - return; - { - GPRTemporary scratch(this); - GPRReg scratchReg = scratch.gpr(); - writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg); - } + speculateArray(arrayMode, child1, baseReg); - speculateArray(child1, baseReg); - - MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())); - if (node.op() == PutByVal) - speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds); - - base.use(); - property.use(); - value.use(); - - // Get the array storage. - GPRTemporary storage(this); - GPRReg storageReg = storage.gpr(); - m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); - - // Check if we're writing to a hole; if so increment m_numValuesInVector. - MacroAssembler::Jump notHoleValue = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); - m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); - - // If we're writing to a hole we might be growing the array; - MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); - m_jit.add32(TrustedImm32(1), propertyReg); - m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); - m_jit.sub32(TrustedImm32(1), propertyReg); - - lengthDoesNotNeedUpdate.link(&m_jit); - notHoleValue.link(&m_jit); + switch (arrayMode) { + case Array::JSArray: + case Array::JSArrayOutOfBounds: { + JSValueOperand value(this, child3); - // Store the value to the array. - m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); - m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); - - if (node.op() == PutByValSafe) { - addSlowPathGenerator( - slowPathCall( - beyondArrayBounds, this, - m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, - NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg)); - } + GPRReg valueTagReg = value.tagGPR(); + GPRReg valuePayloadReg = value.payloadGPR(); - noResult(m_compileIndex, UseChildrenCalledExplicitly); - break; - } - - case PutByValAlias: { - Edge child1 = m_jit.graph().varArgChild(node, 0); - Edge child2 = m_jit.graph().varArgChild(node, 1); - Edge child3 = m_jit.graph().varArgChild(node, 2); - - if (!at(child1).prediction() || !at(child2).prediction()) { - terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); - break; - } - - ASSERT(isActionableMutableArraySpeculation(at(child1).prediction())); - ASSERT(at(child2).shouldSpeculateInteger()); - - SpeculateCellOperand base(this, child1); - SpeculateStrictInt32Operand property(this, child2); - - if (at(child1).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), NoTypedArraySpecCheck, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), NoTypedArraySpecCheck, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), NoTypedArraySpecCheck, SignedTypedArray); if (!m_compileOkay) return; - break; - } - - if (at(child1).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } + + { + GPRTemporary scratch(this); + GPRReg scratchReg = scratch.gpr(); + writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg); + } - if (at(child1).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray, ClampRounding); - if (!m_compileOkay) - return; - break; - } + if (node.op() == PutByValAlias) { + // Get the array storage. + GPRTemporary storage(this); + GPRReg storageReg = storage.gpr(); + m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); + + // Store the value to the array. + GPRReg propertyReg = property.gpr(); + m_jit.store32(value.tagGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(value.payloadGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + + noResult(m_compileIndex); + break; + } - if (at(child1).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), NoTypedArraySpecCheck); - if (!m_compileOkay) - return; - break; + MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())); + if (arrayMode == Array::JSArray) + speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds); + + base.use(); + property.use(); + value.use(); + + // Get the array storage. + GPRTemporary storage(this); + GPRReg storageReg = storage.gpr(); + m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); + + // Check if we're writing to a hole; if so increment m_numValuesInVector. + MacroAssembler::Jump notHoleValue = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); + m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); + + // If we're writing to a hole we might be growing the array; + MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); + m_jit.add32(TrustedImm32(1), propertyReg); + m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); + m_jit.sub32(TrustedImm32(1), propertyReg); + + lengthDoesNotNeedUpdate.link(&m_jit); + notHoleValue.link(&m_jit); + + // Store the value to the array. + m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + + if (arrayMode == Array::JSArrayOutOfBounds) { + addSlowPathGenerator( + slowPathCall( + beyondArrayBounds, this, + m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, + NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg)); + } + + noResult(m_compileIndex, UseChildrenCalledExplicitly); + break; } - - if (at(child1).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), NoTypedArraySpecCheck); - if (!m_compileOkay) - return; - break; + + case Array::Arguments: + // FIXME: we could at some point make this work. Right now we're assuming that the register + // pressure would be too great. + ASSERT_NOT_REACHED(); + break; + + case Array::Int8Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), SignedTypedArray); + break; + + case Array::Int16Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), SignedTypedArray); + break; + + case Array::Int32Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), SignedTypedArray); + break; + + case Array::Uint8Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + + case Array::Uint8ClampedArray: + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray, ClampRounding); + break; + + case Array::Uint16Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), UnsignedTypedArray); + break; + + case Array::Uint32Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), UnsignedTypedArray); + break; + + case Array::Float32Array: + compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float)); + break; + + case Array::Float64Array: + compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double)); + break; + + default: + ASSERT_NOT_REACHED(); + break; } - - ASSERT(at(child1).shouldSpeculateArray()); - - JSValueOperand value(this, child3); - GPRTemporary scratch(this, base); - - GPRReg baseReg = base.gpr(); - GPRReg scratchReg = scratch.gpr(); - - writeBarrier(baseReg, value.tagGPR(), child3, WriteBarrierForPropertyAccess, scratchReg); - - // Get the array storage. - GPRReg storageReg = scratchReg; - m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); - - // Store the value to the array. - GPRReg propertyReg = property.gpr(); - m_jit.store32(value.tagGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); - m_jit.store32(value.payloadGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); - - noResult(m_compileIndex); break; } @@ -2787,7 +2668,7 @@ void SpeculativeJIT::compile(Node& node) writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR); } - speculateArray(node.child1(), baseGPR); + speculateArray(Array::JSArray, node.child1(), baseGPR); GPRTemporary storage(this); GPRReg storageGPR = storage.gpr(); @@ -2827,7 +2708,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg storageGPR = storage.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - speculateArray(node.child1(), baseGPR); + speculateArray(Array::JSArray, node.child1(), baseGPR); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR); @@ -3373,82 +3254,10 @@ void SpeculativeJIT::compile(Node& node) break; } - case GetArrayLength: { - SpeculateCellOperand base(this, node.child1()); - GPRReg baseGPR = base.gpr(); - - speculateArray(node.child1(), baseGPR); - - GPRTemporary result(this); - GPRReg resultGPR = result.gpr(); - - m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR); - m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR); - - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0))); - - integerResult(resultGPR, m_compileIndex); + case GetArrayLength: + compileGetArrayLength(node); break; - } - - case GetArgumentsLength: { - compileGetArgumentsLength(node); - break; - } - - case GetStringLength: { - SpeculateCellOperand base(this, node.child1()); - GPRTemporary result(this); - - GPRReg baseGPR = base.gpr(); - GPRReg resultGPR = result.gpr(); - - if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()))); - m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); - - integerResult(resultGPR, m_compileIndex); - break; - } - - case GetInt8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetInt16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetInt32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint8ClampedArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetFloat32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetFloat64ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case CheckFunction: { SpeculateCellOperand function(this, node.child1()); speculationCheck(BadCache, JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function())); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index c2151088c..c2e207264 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -2374,12 +2374,13 @@ void SpeculativeJIT::compile(Node& node) } case GetByVal: { - if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) { + switch (node.arrayMode()) { + case Array::Undecided: + case Array::ForceExit: + ASSERT_NOT_REACHED(); terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); break; - } - - if (!at(node.child2()).shouldSpeculateInteger() || (!node.child3() && !at(node.child1()).shouldSpeculateArguments())) { + case Array::Generic: { JSValueOperand base(this, node.child1()); JSValueOperand property(this, node.child2()); GPRReg baseGPR = base.gpr(); @@ -2392,120 +2393,90 @@ void SpeculativeJIT::compile(Node& node) jsValueResult(result.gpr(), m_compileIndex); break; } - - if (at(node.child1()).shouldSpeculateArguments()) { - compileGetByValOnArguments(node); + case Array::JSArray: + case Array::JSArrayOutOfBounds: { + SpeculateCellOperand base(this, node.child1()); + SpeculateStrictInt32Operand property(this, node.child2()); + StorageOperand storage(this, node.child3()); + + GPRReg baseReg = base.gpr(); + GPRReg propertyReg = property.gpr(); + GPRReg storageReg = storage.gpr(); + if (!m_compileOkay) return; + + // We will have already speculated that the base is some kind of array, + // at this point. + + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); + + GPRTemporary result(this); + m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr()); + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr())); + + jsValueResult(result.gpr(), m_compileIndex); break; } - - if (at(node.child1()).prediction() == SpecString) { + case Array::String: compileGetByValOnString(node); - if (!m_compileOkay) - return; break; - } - - if (at(node.child1()).shouldSpeculateInt8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateInt16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateInt32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; + case Array::Arguments: + compileGetByValOnArguments(node); + break; + case Array::Int8Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), SignedTypedArray); + break; + case Array::Int16Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), SignedTypedArray); + break; + case Array::Int32Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), SignedTypedArray); + break; + case Array::Uint8Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + case Array::Uint8ClampedArray: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + case Array::Uint16Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), UnsignedTypedArray); + break; + case Array::Uint32Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), UnsignedTypedArray); + break; + case Array::Float32Array: + compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float)); + break; + case Array::Float64Array: + compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double)); + break; + default: + ASSERT_NOT_REACHED(); break; } - - if (at(node.child1()).shouldSpeculateUint16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateFloat32Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateFloat64Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - - SpeculateCellOperand base(this, node.child1()); - SpeculateStrictInt32Operand property(this, node.child2()); - StorageOperand storage(this, node.child3()); - - GPRReg baseReg = base.gpr(); - GPRReg propertyReg = property.gpr(); - GPRReg storageReg = storage.gpr(); - - if (!m_compileOkay) - return; - - // We will have already speculated that the base is some kind of array, - // at this point. - - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); - - GPRTemporary result(this); - m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr()); - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr())); - - jsValueResult(result.gpr(), m_compileIndex); break; } case PutByVal: - case PutByValSafe: { + case PutByValAlias: { Edge child1 = m_jit.graph().varArgChild(node, 0); Edge child2 = m_jit.graph().varArgChild(node, 1); Edge child3 = m_jit.graph().varArgChild(node, 2); - if (!at(child1).prediction() || !at(child2).prediction()) { + Array::Mode arrayMode = modeForPut(node.arrayMode()); + bool alreadyHandled = false; + + switch (arrayMode) { + case Array::Undecided: + case Array::ForceExit: + ASSERT_NOT_REACHED(); terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); + alreadyHandled = true; break; - } - - if (!at(child2).shouldSpeculateInteger()) { + case Array::Generic: { + ASSERT(node.op() == PutByVal); + JSValueOperand arg1(this, child1); JSValueOperand arg2(this, child2); JSValueOperand arg3(this, child3); @@ -2517,19 +2488,97 @@ void SpeculativeJIT::compile(Node& node) callOperation(m_jit.strictModeFor(node.codeOrigin) ? operationPutByValStrict : operationPutByValNonStrict, arg1GPR, arg2GPR, arg3GPR); noResult(m_compileIndex); + alreadyHandled = true; break; } - + default: + break; + } + + if (alreadyHandled) + break; + SpeculateCellOperand base(this, child1); SpeculateStrictInt32Operand property(this, child2); - if (at(child1).shouldSpeculateArguments()) { - dataLog(" in here "); + + GPRReg baseReg = base.gpr(); + GPRReg propertyReg = property.gpr(); + + speculateArray(arrayMode, child1, baseReg); + + switch (arrayMode) { + case Array::JSArray: + case Array::JSArrayOutOfBounds: { + JSValueOperand value(this, child3); + GPRTemporary scratch(this); + + // Map base, property & value into registers, allocate a scratch register. + GPRReg valueReg = value.gpr(); + GPRReg scratchReg = scratch.gpr(); + + if (!m_compileOkay) + return; + + writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg); + + if (node.op() == PutByValAlias) { + GPRReg storageReg = scratchReg; + m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); + + // Store the value to the array. + GPRReg propertyReg = property.gpr(); + GPRReg valueReg = value.gpr(); + m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + + noResult(m_compileIndex); + break; + } + + MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())); + if (arrayMode == Array::JSArray) + speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds); + + base.use(); + property.use(); + value.use(); + + // Get the array storage. + GPRReg storageReg = scratchReg; + m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); + + // Check if we're writing to a hole; if so increment m_numValuesInVector. + MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); + + // If we're writing to a hole we might be growing the array; + MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); + m_jit.add32(TrustedImm32(1), propertyReg); + m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); + m_jit.sub32(TrustedImm32(1), propertyReg); + + lengthDoesNotNeedUpdate.link(&m_jit); + notHoleValue.link(&m_jit); + + // Store the value to the array. + m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + + if (arrayMode == Array::JSArrayOutOfBounds) { + addSlowPathGenerator( + slowPathCall( + beyondArrayBounds, this, + m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, + NoResult, baseReg, propertyReg, valueReg)); + } + + noResult(m_compileIndex, UseChildrenCalledExplicitly); + break; + } + + case Array::Arguments: { JSValueOperand value(this, child3); GPRTemporary scratch(this); GPRTemporary scratch2(this); - GPRReg baseReg = base.gpr(); - GPRReg propertyReg = property.gpr(); GPRReg valueReg = value.gpr(); GPRReg scratchReg = scratch.gpr(); GPRReg scratch2Reg = scratch2.gpr(); @@ -2537,15 +2586,6 @@ void SpeculativeJIT::compile(Node& node) if (!m_compileOkay) return; - if (!isArgumentsSpeculation(m_state.forNode(child1).m_type)) { - speculationCheck( - BadType, JSValueSource::unboxedCell(baseReg), child1, - m_jit.branchPtr( - MacroAssembler::NotEqual, - MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), - MacroAssembler::TrustedImmPtr(&Arguments::s_info))); - } - m_jit.loadPtr( MacroAssembler::Address(baseReg, Arguments::offsetOfData()), scratchReg); @@ -2579,225 +2619,51 @@ void SpeculativeJIT::compile(Node& node) noResult(m_compileIndex); break; } - - if (at(child1).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); + + case Array::Int8Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), SignedTypedArray); break; - } - - if (at(child1).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - JSValueOperand value(this, child3); - GPRTemporary scratch(this); - - // Map base, property & value into registers, allocate a scratch register. - GPRReg baseReg = base.gpr(); - GPRReg propertyReg = property.gpr(); - GPRReg valueReg = value.gpr(); - GPRReg scratchReg = scratch.gpr(); - - if (!m_compileOkay) - return; - - writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg); - - speculateArray(child1, baseReg); - - MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())); - if (node.op() == PutByVal) - speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds); - - base.use(); - property.use(); - value.use(); - - // Get the array storage. - GPRReg storageReg = scratchReg; - m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); - - // Check if we're writing to a hole; if so increment m_numValuesInVector. - MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); - - // If we're writing to a hole we might be growing the array; - MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); - m_jit.add32(TrustedImm32(1), propertyReg); - m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); - m_jit.sub32(TrustedImm32(1), propertyReg); - - lengthDoesNotNeedUpdate.link(&m_jit); - notHoleValue.link(&m_jit); - - // Store the value to the array. - m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - - if (node.op() == PutByValSafe) { - addSlowPathGenerator( - slowPathCall( - beyondArrayBounds, this, - m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, - NoResult, baseReg, propertyReg, valueReg)); - } - - noResult(m_compileIndex, UseChildrenCalledExplicitly); - break; - } - - case PutByValAlias: { - Edge child1 = m_jit.graph().varArgChild(node, 0); - Edge child2 = m_jit.graph().varArgChild(node, 1); - Edge child3 = m_jit.graph().varArgChild(node, 2); - - if (!at(child1).prediction() || !at(child2).prediction()) { - terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); + case Array::Int16Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), SignedTypedArray); break; - } - - ASSERT(isActionableMutableArraySpeculation(at(child1).prediction())); - ASSERT(at(child2).shouldSpeculateInteger()); - - SpeculateCellOperand base(this, child1); - SpeculateStrictInt32Operand property(this, child2); - if (at(child1).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), NoTypedArraySpecCheck, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), NoTypedArraySpecCheck, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), NoTypedArraySpecCheck, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray, ClampRounding); - if (!m_compileOkay) - return; + + case Array::Int32Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), SignedTypedArray); + break; + + case Array::Uint8Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + + case Array::Uint8ClampedArray: + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray, ClampRounding); + break; + + case Array::Uint16Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), UnsignedTypedArray); + break; + + case Array::Uint32Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), UnsignedTypedArray); + break; + + case Array::Float32Array: + compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float)); + break; + + case Array::Float64Array: + compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double)); + break; + + default: + ASSERT_NOT_REACHED(); break; } - if (at(child1).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), NoTypedArraySpecCheck); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), NoTypedArraySpecCheck); - if (!m_compileOkay) - return; - break; - } - - ASSERT(at(child1).shouldSpeculateArray()); - - JSValueOperand value(this, child3); - GPRTemporary scratch(this); - - GPRReg baseReg = base.gpr(); - GPRReg scratchReg = scratch.gpr(); - - writeBarrier(base.gpr(), value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg); - - // Get the array storage. - GPRReg storageReg = scratchReg; - m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); - - // Store the value to the array. - GPRReg propertyReg = property.gpr(); - GPRReg valueReg = value.gpr(); - m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - - noResult(m_compileIndex); break; } - + case RegExpExec: { if (compileRegExpExec(node)) return; @@ -2859,7 +2725,7 @@ void SpeculativeJIT::compile(Node& node) writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR); - speculateArray(node.child1(), baseGPR); + speculateArray(Array::JSArray, node.child1(), baseGPR); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR); @@ -2896,7 +2762,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg storageGPR = storage.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - speculateArray(node.child1(), baseGPR); + speculateArray(Array::JSArray, node.child1(), baseGPR); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR); @@ -3386,81 +3252,10 @@ void SpeculativeJIT::compile(Node& node) break; } - case GetArrayLength: { - SpeculateCellOperand base(this, node.child1()); - GPRTemporary result(this); - - GPRReg baseGPR = base.gpr(); - GPRReg resultGPR = result.gpr(); - - speculateArray(node.child1(), baseGPR); - - m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR); - m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR); - - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0))); - - integerResult(resultGPR, m_compileIndex); + case GetArrayLength: + compileGetArrayLength(node); break; - } - case GetArgumentsLength: { - compileGetArgumentsLength(node); - break; - } - - case GetStringLength: { - SpeculateCellOperand base(this, node.child1()); - GPRTemporary result(this); - - GPRReg baseGPR = base.gpr(); - GPRReg resultGPR = result.gpr(); - - if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()))); - - m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); - - integerResult(resultGPR, m_compileIndex); - break; - } - - case GetInt8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetInt16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetInt32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint8ClampedArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetFloat32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetFloat64ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } case CheckFunction: { SpeculateCellOperand function(this, node.child1()); speculationCheck(BadCache, JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function())); diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp index 68627f95c..eb04a6747 100644 --- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp @@ -98,7 +98,6 @@ public: case GetByVal: case PutByVal: case PutByValAlias: - case PutByValSafe: case GetArrayLength: case Phantom: // Don't count these uses. @@ -215,53 +214,12 @@ public: } case GetByVal: - if (!node.prediction() || !m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction()) - break; - if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) - clobber(live); - break; - case PutByVal: case PutByValAlias: - case PutByValSafe: { - Edge child1 = m_graph.varArgChild(node, 0); - Edge child2 = m_graph.varArgChild(node, 1); - - if (!m_graph[child1].prediction() || !m_graph[child2].prediction()) - break; - if (!m_graph[child2].shouldSpeculateInteger() -#if USE(JSVALUE32_64) - || m_graph[child1].shouldSpeculateArguments() -#endif - ) { - clobber(live); - break; - } - if (node.op() != PutByValSafe) - break; - if (m_graph[child1].shouldSpeculateArguments()) - break; - if (m_graph[child1].shouldSpeculateInt8Array()) - break; - if (m_graph[child1].shouldSpeculateInt16Array()) - break; - if (m_graph[child1].shouldSpeculateInt32Array()) - break; - if (m_graph[child1].shouldSpeculateUint8Array()) - break; - if (m_graph[child1].shouldSpeculateUint8ClampedArray()) - break; - if (m_graph[child1].shouldSpeculateUint16Array()) - break; - if (m_graph[child1].shouldSpeculateUint32Array()) - break; - if (m_graph[child1].shouldSpeculateFloat32Array()) - break; - if (m_graph[child1].shouldSpeculateFloat64Array()) + if (m_graph.byValIsPure(node)) break; clobber(live); break; - } case GetMyArgumentsLengthSafe: case GetMyArgumentByValSafe: diff --git a/Source/JavaScriptCore/heap/GCThreadSharedData.cpp b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp new file mode 100644 index 000000000..82c52d22e --- /dev/null +++ b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2009, 2011 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 "GCThreadSharedData.h" + +#include "JSGlobalData.h" +#include "MarkStack.h" +#include "SlotVisitor.h" +#include <wtf/MainThread.h> + +namespace JSC { + +#if ENABLE(PARALLEL_GC) +void GCThreadSharedData::resetChildren() +{ + for (unsigned i = 0; i < m_markingThreadsMarkStack.size(); ++i) + m_markingThreadsMarkStack[i]->reset(); +} + +size_t GCThreadSharedData::childVisitCount() +{ + unsigned long result = 0; + for (unsigned i = 0; i < m_markingThreadsMarkStack.size(); ++i) + result += m_markingThreadsMarkStack[i]->visitCount(); + return result; +} + +void GCThreadSharedData::markingThreadMain(SlotVisitor* slotVisitor) +{ + WTF::registerGCThread(); + { + ParallelModeEnabler enabler(*slotVisitor); + slotVisitor->drainFromShared(SlotVisitor::SlaveDrain); + } + delete slotVisitor; +} + +void GCThreadSharedData::markingThreadStartFunc(void* myVisitor) +{ + SlotVisitor* slotVisitor = static_cast<SlotVisitor*>(myVisitor); + + slotVisitor->sharedData().markingThreadMain(slotVisitor); +} +#endif + +GCThreadSharedData::GCThreadSharedData(JSGlobalData* globalData) + : m_globalData(globalData) + , m_copiedSpace(&globalData->heap.m_storageSpace) + , m_shouldHashConst(false) + , m_sharedMarkStack(m_segmentAllocator) + , m_numberOfActiveParallelMarkers(0) + , m_parallelMarkersShouldExit(false) +{ +#if ENABLE(PARALLEL_GC) + for (unsigned i = 1; i < Options::numberOfGCMarkers(); ++i) { + SlotVisitor* slotVisitor = new SlotVisitor(*this); + m_markingThreadsMarkStack.append(slotVisitor); + m_markingThreads.append(createThread(markingThreadStartFunc, slotVisitor, "JavaScriptCore::Marking")); + ASSERT(m_markingThreads.last()); + } +#endif +} + +GCThreadSharedData::~GCThreadSharedData() +{ +#if ENABLE(PARALLEL_GC) + // Destroy our marking threads. + { + MutexLocker locker(m_markingLock); + m_parallelMarkersShouldExit = true; + m_markingCondition.broadcast(); + } + for (unsigned i = 0; i < m_markingThreads.size(); ++i) + waitForThreadCompletion(m_markingThreads[i]); +#endif +} + +void GCThreadSharedData::reset() +{ + ASSERT(!m_numberOfActiveParallelMarkers); + ASSERT(!m_parallelMarkersShouldExit); + ASSERT(m_sharedMarkStack.isEmpty()); + +#if ENABLE(PARALLEL_GC) + m_segmentAllocator.shrinkReserve(); + m_opaqueRoots.clear(); +#else + ASSERT(m_opaqueRoots.isEmpty()); +#endif + m_weakReferenceHarvesters.removeAll(); + + if (m_shouldHashConst) { + m_globalData->resetNewStringsSinceLastHashConst(); + m_shouldHashConst = false; + } +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/heap/GCThreadSharedData.h b/Source/JavaScriptCore/heap/GCThreadSharedData.h new file mode 100644 index 000000000..8868b440c --- /dev/null +++ b/Source/JavaScriptCore/heap/GCThreadSharedData.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2009, 2011 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 GCThreadSharedData_h +#define GCThreadSharedData_h + +#include "MarkStack.h" +#include <wtf/Vector.h> + +namespace JSC { + +class JSGlobalData; +class CopiedSpace; + +class GCThreadSharedData { +public: + GCThreadSharedData(JSGlobalData*); + ~GCThreadSharedData(); + + void reset(); + +#if ENABLE(PARALLEL_GC) + void resetChildren(); + size_t childVisitCount(); + size_t childDupStrings(); +#endif + +private: + friend class MarkStack; + friend class SlotVisitor; + +#if ENABLE(PARALLEL_GC) + void markingThreadMain(SlotVisitor*); + static void markingThreadStartFunc(void* heap); +#endif + + JSGlobalData* m_globalData; + CopiedSpace* m_copiedSpace; + + MarkStackSegmentAllocator m_segmentAllocator; + + bool m_shouldHashConst; + + Vector<ThreadIdentifier> m_markingThreads; + Vector<MarkStack*> m_markingThreadsMarkStack; + + Mutex m_markingLock; + ThreadCondition m_markingCondition; + MarkStackArray m_sharedMarkStack; + unsigned m_numberOfActiveParallelMarkers; + bool m_parallelMarkersShouldExit; + + Mutex m_opaqueRootsLock; + HashSet<void*> m_opaqueRoots; + + ListableHandler<WeakReferenceHarvester>::List m_weakReferenceHarvesters; + ListableHandler<UnconditionalFinalizer>::List m_unconditionalFinalizers; +}; + +} // namespace JSC + +#endif diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h index f3474f2ea..6f13afb72 100644 --- a/Source/JavaScriptCore/heap/Heap.h +++ b/Source/JavaScriptCore/heap/Heap.h @@ -24,6 +24,7 @@ #include "BlockAllocator.h" #include "DFGCodeBlocks.h" +#include "GCThreadSharedData.h" #include "HandleSet.h" #include "HandleStack.h" #include "JITStubRoutineSet.h" @@ -74,7 +75,7 @@ namespace JSC { WTF_MAKE_NONCOPYABLE(Heap); public: friend class JIT; - friend class MarkStackThreadSharedData; + friend class GCThreadSharedData; static Heap* heap(const JSValue); // 0 for immediate values static Heap* heap(const JSCell*); @@ -231,7 +232,7 @@ namespace JSC { MachineThreads m_machineThreads; - MarkStackThreadSharedData m_sharedData; + GCThreadSharedData m_sharedData; SlotVisitor m_slotVisitor; HandleSet m_handleSet; diff --git a/Source/JavaScriptCore/heap/ListableHandler.h b/Source/JavaScriptCore/heap/ListableHandler.h index 2cb03251f..16c34146c 100644 --- a/Source/JavaScriptCore/heap/ListableHandler.h +++ b/Source/JavaScriptCore/heap/ListableHandler.h @@ -52,7 +52,7 @@ protected: private: // Allow these classes to use ListableHandler::List. friend class MarkStack; - friend class MarkStackThreadSharedData; + friend class GCThreadSharedData; friend class SlotVisitor; class List { diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp index 02a13077d..9d3062154 100644 --- a/Source/JavaScriptCore/heap/MarkStack.cpp +++ b/Source/JavaScriptCore/heap/MarkStack.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "MarkStack.h" +#include "MarkStackInlineMethods.h" #include "CopiedSpace.h" #include "CopiedSpaceInlineMethods.h" @@ -223,89 +224,22 @@ void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other, size_t idleThread append(other.removeLast()); } -#if ENABLE(PARALLEL_GC) -void MarkStackThreadSharedData::resetChildren() -{ - for (unsigned i = 0; i < m_markingThreadsMarkStack.size(); ++i) - m_markingThreadsMarkStack[i]->reset(); -} - -size_t MarkStackThreadSharedData::childVisitCount() -{ - unsigned long result = 0; - for (unsigned i = 0; i < m_markingThreadsMarkStack.size(); ++i) - result += m_markingThreadsMarkStack[i]->visitCount(); - return result; -} - -void MarkStackThreadSharedData::markingThreadMain(SlotVisitor* slotVisitor) -{ - WTF::registerGCThread(); - { - ParallelModeEnabler enabler(*slotVisitor); - slotVisitor->drainFromShared(SlotVisitor::SlaveDrain); - } - delete slotVisitor; -} - -void MarkStackThreadSharedData::markingThreadStartFunc(void* myVisitor) -{ - SlotVisitor* slotVisitor = static_cast<SlotVisitor*>(myVisitor); - - slotVisitor->sharedData().markingThreadMain(slotVisitor); -} +MarkStack::MarkStack(GCThreadSharedData& shared) + : m_stack(shared.m_segmentAllocator) +#if !ASSERT_DISABLED + , m_isCheckingForDefaultMarkViolation(false) + , m_isDraining(false) #endif - -MarkStackThreadSharedData::MarkStackThreadSharedData(JSGlobalData* globalData) - : m_globalData(globalData) - , m_copiedSpace(&globalData->heap.m_storageSpace) + , m_visitCount(0) + , m_isInParallelMode(false) + , m_shared(shared) , m_shouldHashConst(false) - , m_sharedMarkStack(m_segmentAllocator) - , m_numberOfActiveParallelMarkers(0) - , m_parallelMarkersShouldExit(false) { -#if ENABLE(PARALLEL_GC) - for (unsigned i = 1; i < Options::numberOfGCMarkers(); ++i) { - SlotVisitor* slotVisitor = new SlotVisitor(*this); - m_markingThreadsMarkStack.append(slotVisitor); - m_markingThreads.append(createThread(markingThreadStartFunc, slotVisitor, "JavaScriptCore::Marking")); - ASSERT(m_markingThreads.last()); - } -#endif } -MarkStackThreadSharedData::~MarkStackThreadSharedData() +MarkStack::~MarkStack() { -#if ENABLE(PARALLEL_GC) - // Destroy our marking threads. - { - MutexLocker locker(m_markingLock); - m_parallelMarkersShouldExit = true; - m_markingCondition.broadcast(); - } - for (unsigned i = 0; i < m_markingThreads.size(); ++i) - waitForThreadCompletion(m_markingThreads[i]); -#endif -} - -void MarkStackThreadSharedData::reset() -{ - ASSERT(!m_numberOfActiveParallelMarkers); - ASSERT(!m_parallelMarkersShouldExit); - ASSERT(m_sharedMarkStack.isEmpty()); - -#if ENABLE(PARALLEL_GC) - m_segmentAllocator.shrinkReserve(); - m_opaqueRoots.clear(); -#else - ASSERT(m_opaqueRoots.isEmpty()); -#endif - m_weakReferenceHarvesters.removeAll(); - - if (m_shouldHashConst) { - m_globalData->resetNewStringsSinceLastHashConst(); - m_shouldHashConst = false; - } + ASSERT(m_stack.isEmpty()); } void MarkStack::setup() diff --git a/Source/JavaScriptCore/heap/MarkStack.h b/Source/JavaScriptCore/heap/MarkStack.h index 467a5bf46..54ae1cb02 100644 --- a/Source/JavaScriptCore/heap/MarkStack.h +++ b/Source/JavaScriptCore/heap/MarkStack.h @@ -74,6 +74,7 @@ namespace JSC { class ConservativeRoots; class JSGlobalData; class MarkStack; + class GCThreadSharedData; class ParallelModeEnabler; class Register; class SlotVisitor; @@ -192,57 +193,12 @@ namespace JSC { #endif }; - class MarkStackThreadSharedData { - public: - MarkStackThreadSharedData(JSGlobalData*); - ~MarkStackThreadSharedData(); - - void reset(); - -#if ENABLE(PARALLEL_GC) - void resetChildren(); - size_t childVisitCount(); - size_t childDupStrings(); -#endif - - private: - friend class MarkStack; - friend class SlotVisitor; - -#if ENABLE(PARALLEL_GC) - void markingThreadMain(SlotVisitor*); - static void markingThreadStartFunc(void* heap); -#endif - - JSGlobalData* m_globalData; - CopiedSpace* m_copiedSpace; - - MarkStackSegmentAllocator m_segmentAllocator; - - bool m_shouldHashConst; - - Vector<ThreadIdentifier> m_markingThreads; - Vector<MarkStack*> m_markingThreadsMarkStack; - - Mutex m_markingLock; - ThreadCondition m_markingCondition; - MarkStackArray m_sharedMarkStack; - unsigned m_numberOfActiveParallelMarkers; - bool m_parallelMarkersShouldExit; - - Mutex m_opaqueRootsLock; - HashSet<void*> m_opaqueRoots; - - ListableHandler<WeakReferenceHarvester>::List m_weakReferenceHarvesters; - ListableHandler<UnconditionalFinalizer>::List m_unconditionalFinalizers; - }; - class MarkStack { WTF_MAKE_NONCOPYABLE(MarkStack); friend class HeapRootVisitor; // Allowed to mark a JSValue* or JSCell** directly. public: - MarkStack(MarkStackThreadSharedData&); + MarkStack(GCThreadSharedData&); ~MarkStack(); void append(ConservativeRoots&); @@ -259,7 +215,7 @@ namespace JSC { bool containsOpaqueRoot(void*); int opaqueRootCount(); - MarkStackThreadSharedData& sharedData() { return m_shared; } + GCThreadSharedData& sharedData() { return m_shared; } bool isEmpty() { return m_stack.isEmpty(); } void setup(); @@ -271,15 +227,8 @@ namespace JSC { VTableSpectrum m_visitedTypeCounts; #endif - void addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester) - { - m_shared.m_weakReferenceHarvesters.addThreadSafe(weakReferenceHarvester); - } - - void addUnconditionalFinalizer(UnconditionalFinalizer* unconditionalFinalizer) - { - m_shared.m_unconditionalFinalizers.addThreadSafe(unconditionalFinalizer); - } + void addWeakReferenceHarvester(WeakReferenceHarvester*); + void addUnconditionalFinalizer(UnconditionalFinalizer*); #if ENABLE(OBJECT_MARK_LOGGING) inline void resetChildCount() { m_logChildCount = 0; } @@ -328,7 +277,7 @@ namespace JSC { size_t m_visitCount; bool m_isInParallelMode; - MarkStackThreadSharedData& m_shared; + GCThreadSharedData& m_shared; bool m_shouldHashConst; // Local per-thread copy of shared flag for performance reasons typedef HashMap<StringImpl*, JSValue> UniqueStringMap; @@ -339,63 +288,6 @@ namespace JSC { #endif }; - inline MarkStack::MarkStack(MarkStackThreadSharedData& shared) - : m_stack(shared.m_segmentAllocator) -#if !ASSERT_DISABLED - , m_isCheckingForDefaultMarkViolation(false) - , m_isDraining(false) -#endif - , m_visitCount(0) - , m_isInParallelMode(false) - , m_shared(shared) - , m_shouldHashConst(false) - { - } - - inline MarkStack::~MarkStack() - { - ASSERT(m_stack.isEmpty()); - } - - inline void MarkStack::addOpaqueRoot(void* root) - { -#if ENABLE(PARALLEL_GC) - if (Options::numberOfGCMarkers() == 1) { - // Put directly into the shared HashSet. - m_shared.m_opaqueRoots.add(root); - return; - } - // Put into the local set, but merge with the shared one every once in - // a while to make sure that the local sets don't grow too large. - mergeOpaqueRootsIfProfitable(); - m_opaqueRoots.add(root); -#else - m_opaqueRoots.add(root); -#endif - } - - inline bool MarkStack::containsOpaqueRoot(void* root) - { - ASSERT(!m_isInParallelMode); -#if ENABLE(PARALLEL_GC) - ASSERT(m_opaqueRoots.isEmpty()); - return m_shared.m_opaqueRoots.contains(root); -#else - return m_opaqueRoots.contains(root); -#endif - } - - inline int MarkStack::opaqueRootCount() - { - ASSERT(!m_isInParallelMode); -#if ENABLE(PARALLEL_GC) - ASSERT(m_opaqueRoots.isEmpty()); - return m_shared.m_opaqueRoots.size(); -#else - return m_opaqueRoots.size(); -#endif - } - inline void MarkStackArray::append(const JSCell* cell) { if (m_top == m_segmentCapacity) @@ -429,51 +321,6 @@ namespace JSC { return m_top + m_segmentCapacity * m_numberOfPreviousSegments; } - ALWAYS_INLINE void MarkStack::append(JSValue* slot, size_t count) - { - for (size_t i = 0; i < count; ++i) { - JSValue& value = slot[i]; - if (!value) - continue; - internalAppend(value); - } - } - - template<typename T> - inline void MarkStack::appendUnbarrieredPointer(T** slot) - { - ASSERT(slot); - JSCell* cell = *slot; - if (cell) - internalAppend(cell); - } - - ALWAYS_INLINE void MarkStack::append(JSValue* slot) - { - ASSERT(slot); - internalAppend(*slot); - } - - ALWAYS_INLINE void MarkStack::appendUnbarrieredValue(JSValue* slot) - { - ASSERT(slot); - internalAppend(*slot); - } - - ALWAYS_INLINE void MarkStack::append(JSCell** slot) - { - ASSERT(slot); - internalAppend(*slot); - } - - ALWAYS_INLINE void MarkStack::internalAppend(JSValue value) - { - ASSERT(value); - if (!value.isCell()) - return; - internalAppend(value.asCell()); - } - class ParallelModeEnabler { public: ParallelModeEnabler(MarkStack& stack) diff --git a/Source/JavaScriptCore/heap/MarkStackInlineMethods.h b/Source/JavaScriptCore/heap/MarkStackInlineMethods.h new file mode 100644 index 000000000..8b420d637 --- /dev/null +++ b/Source/JavaScriptCore/heap/MarkStackInlineMethods.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2009, 2011 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 MarkStackInlineMethods_h +#define MarkStackInlineMethods_h + +#include "GCThreadSharedData.h" +#include "MarkStack.h" + +namespace JSC { + +ALWAYS_INLINE void MarkStack::append(JSValue* slot, size_t count) +{ + for (size_t i = 0; i < count; ++i) { + JSValue& value = slot[i]; + if (!value) + continue; + internalAppend(value); + } +} + +template<typename T> +inline void MarkStack::appendUnbarrieredPointer(T** slot) +{ + ASSERT(slot); + JSCell* cell = *slot; + if (cell) + internalAppend(cell); +} + +ALWAYS_INLINE void MarkStack::append(JSValue* slot) +{ + ASSERT(slot); + internalAppend(*slot); +} + +ALWAYS_INLINE void MarkStack::appendUnbarrieredValue(JSValue* slot) +{ + ASSERT(slot); + internalAppend(*slot); +} + +ALWAYS_INLINE void MarkStack::append(JSCell** slot) +{ + ASSERT(slot); + internalAppend(*slot); +} + +ALWAYS_INLINE void MarkStack::internalAppend(JSValue value) +{ + ASSERT(value); + if (!value.isCell()) + return; + internalAppend(value.asCell()); +} + +inline void MarkStack::addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester) +{ + m_shared.m_weakReferenceHarvesters.addThreadSafe(weakReferenceHarvester); +} + +inline void MarkStack::addUnconditionalFinalizer(UnconditionalFinalizer* unconditionalFinalizer) +{ + m_shared.m_unconditionalFinalizers.addThreadSafe(unconditionalFinalizer); +} + +inline void MarkStack::addOpaqueRoot(void* root) +{ +#if ENABLE(PARALLEL_GC) + if (Options::numberOfGCMarkers() == 1) { + // Put directly into the shared HashSet. + m_shared.m_opaqueRoots.add(root); + return; + } + // Put into the local set, but merge with the shared one every once in + // a while to make sure that the local sets don't grow too large. + mergeOpaqueRootsIfProfitable(); + m_opaqueRoots.add(root); +#else + m_opaqueRoots.add(root); +#endif +} + +inline bool MarkStack::containsOpaqueRoot(void* root) +{ + ASSERT(!m_isInParallelMode); +#if ENABLE(PARALLEL_GC) + ASSERT(m_opaqueRoots.isEmpty()); + return m_shared.m_opaqueRoots.contains(root); +#else + return m_opaqueRoots.contains(root); +#endif +} + +inline int MarkStack::opaqueRootCount() +{ + ASSERT(!m_isInParallelMode); +#if ENABLE(PARALLEL_GC) + ASSERT(m_opaqueRoots.isEmpty()); + return m_shared.m_opaqueRoots.size(); +#else + return m_opaqueRoots.size(); +#endif +} + +} // namespace JSC + +#endif diff --git a/Source/JavaScriptCore/heap/SlotVisitor.h b/Source/JavaScriptCore/heap/SlotVisitor.h index a31e88c08..6364b23e4 100644 --- a/Source/JavaScriptCore/heap/SlotVisitor.h +++ b/Source/JavaScriptCore/heap/SlotVisitor.h @@ -28,15 +28,17 @@ #include "CopiedSpace.h" #include "MarkStack.h" +#include "MarkStackInlineMethods.h" namespace JSC { class Heap; +class GCThreadSharedData; class SlotVisitor : public MarkStack { friend class HeapRootVisitor; public: - SlotVisitor(MarkStackThreadSharedData&); + SlotVisitor(GCThreadSharedData&); void donate() { @@ -85,7 +87,7 @@ private: CopiedAllocator m_copiedAllocator; }; -inline SlotVisitor::SlotVisitor(MarkStackThreadSharedData& shared) +inline SlotVisitor::SlotVisitor(GCThreadSharedData& shared) : MarkStack(shared) { } diff --git a/Source/JavaScriptCore/parser/SourceProvider.h b/Source/JavaScriptCore/parser/SourceProvider.h index 946792b2c..2e7f71785 100644 --- a/Source/JavaScriptCore/parser/SourceProvider.h +++ b/Source/JavaScriptCore/parser/SourceProvider.h @@ -49,8 +49,8 @@ namespace JSC { , m_cache(cache ? cache : new SourceProviderCache) , m_cacheOwned(!cache) { - turnOffVerifier(); } + virtual ~SourceProvider() { if (m_cacheOwned) diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h index 9ddc32c8c..8b017efbc 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.h +++ b/Source/JavaScriptCore/runtime/SymbolTable.h @@ -330,7 +330,7 @@ namespace JSC { public: static PassRefPtr<SharedSymbolTable> create() { return adoptRef(new SharedSymbolTable); } private: - SharedSymbolTable() { turnOffVerifier(); } + SharedSymbolTable() { } }; } // namespace JSC |