summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore')
-rw-r--r--Source/JavaScriptCore/CMakeLists.txt2
-rw-r--r--Source/JavaScriptCore/ChangeLog168
-rw-r--r--Source/JavaScriptCore/GNUmakefile.list.am5
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj12
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj28
-rw-r--r--Source/JavaScriptCore/Target.pri2
-rw-r--r--Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp2
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp314
-rw-r--r--Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp79
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.cpp217
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.h135
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp63
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp21
-rw-r--r--Source/JavaScriptCore/dfg/DFGFixupPhase.cpp176
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.cpp4
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h55
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h29
-rw-r--r--Source/JavaScriptCore/dfg/DFGNodeType.h12
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp12
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp254
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h20
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp585
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp595
-rw-r--r--Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp44
-rw-r--r--Source/JavaScriptCore/heap/GCThreadSharedData.cpp121
-rw-r--r--Source/JavaScriptCore/heap/GCThreadSharedData.h84
-rw-r--r--Source/JavaScriptCore/heap/Heap.h5
-rw-r--r--Source/JavaScriptCore/heap/ListableHandler.h2
-rw-r--r--Source/JavaScriptCore/heap/MarkStack.cpp88
-rw-r--r--Source/JavaScriptCore/heap/MarkStack.h165
-rw-r--r--Source/JavaScriptCore/heap/MarkStackInlineMethods.h130
-rw-r--r--Source/JavaScriptCore/heap/SlotVisitor.h6
-rw-r--r--Source/JavaScriptCore/parser/SourceProvider.h2
-rw-r--r--Source/JavaScriptCore/runtime/SymbolTable.h2
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