WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
better
blah.patch (text/plain), 74.72 KB, created by
Filip Pizlo
on 2014-09-30 20:41:42 PDT
(
hide
)
Description:
better
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2014-09-30 20:41:42 PDT
Size:
74.72 KB
patch
obsolete
>Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 174045) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,55 @@ >+2014-09-28 Filip Pizlo <fpizlo@apple.com> >+ >+ FTL should sink SetLocals >+ https://bugs.webkit.org/show_bug.cgi?id=137168 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Work in progress. >+ >+ * CMakeLists.txt: >+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * bytecode/CodeBlock.h: >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): >+ * dfg/DFGClobberSet.h: >+ (JSC::DFG::ClobberSetAdd::operator()): >+ (JSC::DFG::ClobberSetOverlaps::operator()): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ (JSC::DFG::NoOpClobberize::operator()): >+ (JSC::DFG::CheckClobberize::operator()): >+ (JSC::DFG::AbstractHeapOverlaps::operator()): >+ (JSC::DFG::ReadMethodClobberize::operator()): >+ (JSC::DFG::WriteMethodClobberize::operator()): >+ (JSC::DFG::DefMethodClobberize::operator()): >+ * dfg/DFGFlushFormat.h: >+ (JSC::DFG::merge): >+ * dfg/DFGGraph.cpp: >+ (JSC::DFG::Graph::Graph): >+ * dfg/DFGGraph.h: >+ (JSC::DFG::Graph::capturedVarsFor): >+ * dfg/DFGPlan.cpp: >+ (JSC::DFG::Plan::compileInThreadImpl): >+ * dfg/DFGPreciseLocalClobberize.h: Added. >+ (JSC::DFG::PreciseLocalClobberizeAdaptor::PreciseLocalClobberizeAdaptor): >+ (JSC::DFG::PreciseLocalClobberizeAdaptor::read): >+ (JSC::DFG::PreciseLocalClobberizeAdaptor::write): >+ (JSC::DFG::PreciseLocalClobberizeAdaptor::def): >+ (JSC::DFG::PreciseLocalClobberizeAdaptor::readTop): >+ (JSC::DFG::PreciseLocalClobberizeAdaptor::writeTop): >+ (JSC::DFG::preciseLocalClobberize): >+ * dfg/DFGSSACalculator.h: >+ (JSC::DFG::SSACalculator::computePhis): >+ * dfg/DFGSetLocalSinkingPhase.cpp: Added. >+ (JSC::DFG::SetLocalSinkingPhase::SetLocalSinkingPhase): >+ (JSC::DFG::SetLocalSinkingPhase::run): >+ (JSC::DFG::SetLocalSinkingPhase::materialize): >+ (JSC::DFG::performSetLocalSinking): >+ * dfg/DFGSetLocalSinkingPhase.h: Added. >+ * runtime/Options.h: >+ > 2014-09-26 Filip Pizlo <fpizlo@apple.com> > > Disable function.arguments >Index: Source/JavaScriptCore/CMakeLists.txt >=================================================================== >--- Source/JavaScriptCore/CMakeLists.txt (revision 174031) >+++ Source/JavaScriptCore/CMakeLists.txt (working copy) >@@ -207,6 +207,7 @@ set(JavaScriptCore_SOURCES > dfg/DFGPredictionPropagationPhase.cpp > dfg/DFGPromotedHeapLocation.cpp > dfg/DFGPureValue.cpp >+ dfg/DFGPutLocalSinkingPhase.cpp > dfg/DFGResurrectionForValidationPhase.cpp > dfg/DFGSSACalculator.cpp > dfg/DFGSSAConversionPhase.cpp >Index: Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj >=================================================================== >--- Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (revision 174031) >+++ Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (working copy) >@@ -453,6 +453,7 @@ > <ClCompile Include="..\dfg\DFGPredictionPropagationPhase.cpp" /> > <ClCompile Include="..\dfg\DFGPromotedHeapLocation.cpp" /> > <ClCompile Include="..\dfg\DFGPureValue.cpp" /> >+ <ClCompile Include="..\dfg\DFGPutLocalSinkingPhase.cpp" /> > <ClCompile Include="..\dfg\DFGResurrectionForValidationPhase.cpp" /> > <ClCompile Include="..\dfg\DFGSafepoint.cpp" /> > <ClCompile Include="..\dfg\DFGSpeculativeJIT.cpp" /> >@@ -1104,11 +1105,13 @@ > <ClInclude Include="..\dfg\DFGPhiChildren.h" /> > <ClInclude Include="..\dfg\DFGPlan.h" /> > <ClInclude Include="..\dfg\DFGPrePostNumbering.h" /> >+ <ClInclude Include="..\dfg\DFGPreciseLocalClobberize.h" /> > <ClInclude Include="..\dfg\DFGPredictionInjectionPhase.h" /> > <ClInclude Include="..\dfg\DFGPredictionPropagationPhase.h" /> > <ClInclude Include="..\dfg\DFGPromoteHeapAccess.h" /> > <ClInclude Include="..\dfg\DFGPromotedHeapLocation.h" /> > <ClInclude Include="..\dfg\DFGPureValue.h" /> >+ <ClInclude Include="..\dfg\DFGPutLocalSinkingPhase.h" /> > <ClInclude Include="..\dfg\DFGRegisterBank.h" /> > <ClInclude Include="..\dfg\DFGRegisterSet.h" /> > <ClInclude Include="..\dfg\DFGResurrectionForValidationPhase.h" /> >Index: Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >=================================================================== >--- Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (revision 174031) >+++ Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (working copy) >@@ -1562,6 +1562,9 @@ > C49FE4AA19AAC83E00F40CE9 /* generate_protocol_types_implementation.py in Resources */ = {isa = PBXBuildFile; fileRef = C49FE4A819AAC83E00F40CE9 /* generate_protocol_types_implementation.py */; }; > C49FE4AB19AAC86100F40CE9 /* generate_protocol_types_header.py in Headers */ = {isa = PBXBuildFile; fileRef = C49FE4A719AAC83E00F40CE9 /* generate_protocol_types_header.py */; settings = {ATTRIBUTES = (Private, ); }; }; > C49FE4AC19AAC86100F40CE9 /* generate_protocol_types_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = C49FE4A819AAC83E00F40CE9 /* generate_protocol_types_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; }; >+ DC00039319D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h in Headers */ = {isa = PBXBuildFile; fileRef = DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ DC00039819DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC00039619DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp */; }; >+ DC00039919DBA70600023EB0 /* DFGPutLocalSinkingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = DC00039719DBA70600023EB0 /* DFGPutLocalSinkingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; > E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */ = {isa = PBXBuildFile; fileRef = E124A8F50E555775003091F1 /* OpaqueJSString.h */; settings = {ATTRIBUTES = (Private, ); }; }; > E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E124A8F60E555775003091F1 /* OpaqueJSString.cpp */; }; > E18E3A590DF9278C00D90B34 /* VM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18E3A570DF9278C00D90B34 /* VM.cpp */; }; >@@ -3222,6 +3225,9 @@ > C49FE4A819AAC83E00F40CE9 /* generate_protocol_types_implementation.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_protocol_types_implementation.py; sourceTree = "<group>"; }; > D21202280AD4310C00ED79B6 /* DateConversion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DateConversion.cpp; sourceTree = "<group>"; }; > D21202290AD4310C00ED79B6 /* DateConversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DateConversion.h; sourceTree = "<group>"; }; >+ DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPreciseLocalClobberize.h; path = dfg/DFGPreciseLocalClobberize.h; sourceTree = "<group>"; }; >+ DC00039619DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPutLocalSinkingPhase.cpp; path = dfg/DFGPutLocalSinkingPhase.cpp; sourceTree = "<group>"; }; >+ DC00039719DBA70600023EB0 /* DFGPutLocalSinkingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPutLocalSinkingPhase.h; path = dfg/DFGPutLocalSinkingPhase.h; sourceTree = "<group>"; }; > E124A8F50E555775003091F1 /* OpaqueJSString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpaqueJSString.h; sourceTree = "<group>"; }; > E124A8F60E555775003091F1 /* OpaqueJSString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpaqueJSString.cpp; sourceTree = "<group>"; }; > E178633F0D9BEC0000D74E75 /* InitializeThreading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeThreading.h; sourceTree = "<group>"; }; >@@ -4755,6 +4761,7 @@ > 0F2B9CDF19D0BA7D00B1D1B5 /* DFGPhiChildren.h */, > A78A9772179738B8009DF744 /* DFGPlan.cpp */, > A78A9773179738B8009DF744 /* DFGPlan.h */, >+ DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */, > 0FBE0F6D16C1DB010082C5E8 /* DFGPredictionInjectionPhase.cpp */, > 0FBE0F6E16C1DB010082C5E8 /* DFGPredictionInjectionPhase.h */, > 0FFFC95114EF909500C72532 /* DFGPredictionPropagationPhase.cpp */, >@@ -4766,6 +4773,8 @@ > 0FAA3E0819D0C2CB00FAC9E2 /* DFGPromoteHeapAccess.h */, > 0FB1765E196B8F9E0091052A /* DFGPureValue.cpp */, > 0FB1765F196B8F9E0091052A /* DFGPureValue.h */, >+ DC00039619DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp */, >+ DC00039719DBA70600023EB0 /* DFGPutLocalSinkingPhase.h */, > 86EC9DC11328DF82002B2AD7 /* DFGRegisterBank.h */, > 0F666ECA1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp */, > 0F666ECB1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h */, >@@ -5586,6 +5595,7 @@ > 0FEA0A08170513DB00BB722C /* FTLAbbreviations.h in Headers */, > A53CE08A18BC21C300BEDF76 /* ConsoleClient.h in Headers */, > 0FEA0A1D1708B00700BB722C /* FTLAbstractHeap.h in Headers */, >+ DC00039319D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h in Headers */, > 0FEA0A1F1708B00700BB722C /* FTLAbstractHeapRepository.h in Headers */, > 0F485328187DFDEC0083B687 /* FTLAvailableRecovery.h in Headers */, > 0FEA0A0A170513DB00BB722C /* FTLCapabilities.h in Headers */, >@@ -5844,6 +5854,7 @@ > BC18C4280E16F5CD00B34460 /* JSStringRef.h in Headers */, > BC18C4290E16F5CD00B34460 /* JSStringRefCF.h in Headers */, > 1A28D4A8177B71C80007FA3C /* JSStringRefPrivate.h in Headers */, >+ DC00039919DBA70600023EB0 /* DFGPutLocalSinkingPhase.h in Headers */, > 0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */, > BC18C42A0E16F5CD00B34460 /* JSType.h in Headers */, > 0F2B66FB17B6B5AB00A7AE3F /* JSTypedArrayConstructors.h in Headers */, >@@ -6719,6 +6730,7 @@ > A7D89CF517A0B8CC00773AD8 /* DFGCriticalEdgeBreakingPhase.cpp in Sources */, > 0FFFC95914EF90A600C72532 /* DFGCSEPhase.cpp in Sources */, > 0F2FC77216E12F710038D976 /* DFGDCEPhase.cpp in Sources */, >+ DC00039819DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp in Sources */, > 0F8F2B99172F04FF007DBDA5 /* DFGDesiredIdentifiers.cpp in Sources */, > C2C0F7CD17BBFC5B00464FE4 /* DFGDesiredTransitions.cpp in Sources */, > 0FE8534B1723CDA500B618F5 /* DFGDesiredWatchpoints.cpp in Sources */, >Index: Source/JavaScriptCore/bytecode/CodeBlock.h >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeBlock.h (revision 174031) >+++ Source/JavaScriptCore/bytecode/CodeBlock.h (working copy) >@@ -384,7 +384,7 @@ public: > return 0; > return symbolTable()->captureEnd(); > } >- >+ > bool isCaptured(VirtualRegister operand, InlineCallFrame* = 0) const; > > int framePointerOffsetToGetActivationRegisters(int machineCaptureStart); >Index: Source/JavaScriptCore/bytecode/Operands.h >=================================================================== >--- Source/JavaScriptCore/bytecode/Operands.h (revision 174031) >+++ Source/JavaScriptCore/bytecode/Operands.h (working copy) >@@ -252,11 +252,7 @@ public: > } > > void dumpInContext(PrintStream& out, DumpContext* context) const; >- >- void dump(PrintStream& out) const >- { >- dumpInContext(out, 0); >- } >+ void dump(PrintStream& out) const; > > private: > Vector<T, 8> m_arguments; >Index: Source/JavaScriptCore/bytecode/OperandsInlines.h >=================================================================== >--- Source/JavaScriptCore/bytecode/OperandsInlines.h (revision 174031) >+++ Source/JavaScriptCore/bytecode/OperandsInlines.h (working copy) >@@ -47,6 +47,22 @@ void Operands<T, Traits>::dumpInContext( > } > } > >+template<typename T, typename Traits> >+void Operands<T, Traits>::dump(PrintStream& out) const >+{ >+ CommaPrinter comma(" "); >+ for (size_t argumentIndex = numberOfArguments(); argumentIndex--;) { >+ if (Traits::isEmptyForDump(argument(argumentIndex))) >+ continue; >+ out.print(comma, "arg", argumentIndex, ":", argument(argumentIndex)); >+ } >+ for (size_t localIndex = 0; localIndex < numberOfLocals(); ++localIndex) { >+ if (Traits::isEmptyForDump(local(localIndex))) >+ continue; >+ out.print(comma, "loc", localIndex, ":", local(localIndex)); >+ } >+} >+ > } // namespace JSC > > #endif // OperandsInlines_h >Index: Source/JavaScriptCore/bytecode/VirtualRegister.h >=================================================================== >--- Source/JavaScriptCore/bytecode/VirtualRegister.h (revision 174031) >+++ Source/JavaScriptCore/bytecode/VirtualRegister.h (working copy) >@@ -59,6 +59,7 @@ public: > bool isValid() const { return (m_virtualRegister != s_invalidVirtualRegister); } > bool isLocal() const { return operandIsLocal(m_virtualRegister); } > bool isArgument() const { return operandIsArgument(m_virtualRegister); } >+ bool isHeader() const { return m_virtualRegister >= 0 && m_virtualRegister < JSStack::ThisArgument; } > bool isConstant() const { return m_virtualRegister >= s_firstConstantRegisterIndex; } > int toLocal() const { ASSERT(isLocal()); return operandToLocal(m_virtualRegister); } > int toArgument() const { ASSERT(isArgument()); return operandToArgument(m_virtualRegister); } >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (working copy) >@@ -183,7 +183,8 @@ bool AbstractInterpreter<AbstractStateTy > break; > } > >- case SetLocal: { >+ case SetLocal: >+ case PutLocal: { > m_state.variables().operand(node->local().offset()) = forNode(node->child1()); > break; > } >@@ -195,6 +196,12 @@ bool AbstractInterpreter<AbstractStateTy > break; > } > >+ case KillLocal: { >+ // This is just a hint telling us that the OSR state of the local is no longer inside the >+ // flushed data. >+ break; >+ } >+ > case SetArgument: > // Assert that the state of arguments has been set. > ASSERT(!m_state.block()->valuesAtHead.operand(node->local()).isClear()); >Index: Source/JavaScriptCore/dfg/DFGAvailability.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAvailability.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGAvailability.h (working copy) >@@ -81,6 +81,21 @@ public: > return withNode(unavailableMarker()); > } > >+ void setFlush(FlushedAt flushedAt) >+ { >+ m_flushedAt = flushedAt; >+ } >+ >+ void setNode(Node* node) >+ { >+ m_node = node; >+ } >+ >+ void setNodeUnavailable() >+ { >+ m_node = unavailableMarker(); >+ } >+ > bool nodeIsUndecided() const { return !m_node; } > bool nodeIsUnavailable() const { return m_node == unavailableMarker(); } > >Index: Source/JavaScriptCore/dfg/DFGBasicBlock.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGBasicBlock.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGBasicBlock.cpp (working copy) >@@ -89,6 +89,16 @@ bool BasicBlock::isInBlock(Node* myNode) > return false; > } > >+NodeOrigin BasicBlock::firstOrigin() >+{ >+ for (Node* node : *this) { >+ if (node->origin.isSet()) >+ return node->origin; >+ } >+ RELEASE_ASSERT_NOT_REACHED(); >+ return NodeOrigin(); >+} >+ > void BasicBlock::removePredecessor(BasicBlock* block) > { > for (unsigned i = 0; i < predecessors.size(); ++i) { >Index: Source/JavaScriptCore/dfg/DFGBasicBlock.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGBasicBlock.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGBasicBlock.h (working copy) >@@ -34,6 +34,7 @@ > #include "DFGBranchDirection.h" > #include "DFGFlushedAt.h" > #include "DFGNode.h" >+#include "DFGNodeOrigin.h" > #include "DFGStructureClobberState.h" > #include "Operands.h" > #include <wtf/HashMap.h> >@@ -90,6 +91,8 @@ struct BasicBlock : RefCounted<BasicBloc > BlockNodeList::iterator begin() { return m_nodes.begin(); } > BlockNodeList::iterator end() { return m_nodes.end(); } > >+ NodeOrigin firstOrigin(); >+ > unsigned numSuccessors() { return last()->numSuccessors(); } > > BasicBlock*& successor(unsigned index) >Index: Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (working copy) >@@ -3693,12 +3693,8 @@ ByteCodeParser::InlineStackEntry::Inline > > if (m_inlineCallFrame->caller.inlineCallFrame) > m_inlineCallFrame->capturedVars = m_inlineCallFrame->caller.inlineCallFrame->capturedVars; >- else { >- for (int i = byteCodeParser->m_codeBlock->m_numVars; i--;) { >- if (byteCodeParser->m_codeBlock->isCaptured(virtualRegisterForLocal(i))) >- m_inlineCallFrame->capturedVars.set(i); >- } >- } >+ else >+ m_inlineCallFrame->capturedVars = byteCodeParser->m_graph.m_outermostCapturedVars; > > for (int i = argumentCountIncludingThis; i--;) { > VirtualRegister argument = virtualRegisterForArgument(i); >Index: Source/JavaScriptCore/dfg/DFGClobberSet.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGClobberSet.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGClobberSet.h (working copy) >@@ -80,7 +80,7 @@ public: > { > } > >- void operator()(AbstractHeap heap) >+ void operator()(AbstractHeap heap) const > { > m_set.add(heap); > } >@@ -96,7 +96,7 @@ public: > { > } > >- void operator()(AbstractHeap heap) >+ void operator()(AbstractHeap heap) const > { > m_result |= m_set.overlaps(heap); > } >@@ -105,7 +105,7 @@ public: > > private: > const ClobberSet& m_set; >- bool m_result; >+ mutable bool m_result; > }; > > void addReads(Graph&, Node*, ClobberSet&); >Index: Source/JavaScriptCore/dfg/DFGClobberize.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGClobberize.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGClobberize.h (working copy) >@@ -1,4 +1,4 @@ >- /* >+/* > * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without >@@ -37,7 +37,7 @@ > namespace JSC { namespace DFG { > > template<typename ReadFunctor, typename WriteFunctor, typename DefFunctor> >-void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write, DefFunctor& def) >+void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFunctor& write, const DefFunctor& def) > { > // Some notes: > // >@@ -252,6 +252,7 @@ void clobberize(Graph& graph, Node* node > > case MovHint: > case ZombieHint: >+ case KillLocal: > case Upsilon: > case Phi: > case PhantomLocal: >@@ -395,6 +396,7 @@ void clobberize(Graph& graph, Node* node > return; > > case SetLocal: >+ case PutLocal: > write(AbstractHeap(Variables, node->local())); > def(HeapLocation(VariableLoc, AbstractHeap(Variables, node->local())), node->child1().node()); > return; >@@ -899,7 +901,7 @@ class NoOpClobberize { > public: > NoOpClobberize() { } > template<typename... T> >- void operator()(T...) { } >+ void operator()(T...) const { } > }; > > class CheckClobberize { >@@ -910,12 +912,12 @@ public: > } > > template<typename... T> >- void operator()(T...) { m_result = true; } >+ void operator()(T...) const { m_result = true; } > > bool result() const { return m_result; } > > private: >- bool m_result; >+ mutable bool m_result; > }; > > bool doesWrites(Graph&, Node*); >@@ -928,7 +930,7 @@ public: > { > } > >- void operator()(AbstractHeap otherHeap) >+ void operator()(AbstractHeap otherHeap) const > { > if (m_result) > return; >@@ -939,7 +941,7 @@ public: > > private: > AbstractHeap m_heap; >- bool m_result; >+ mutable bool m_result; > }; > > bool accessesOverlap(Graph&, Node*, AbstractHeap); >@@ -956,7 +958,7 @@ public: > { > } > >- void operator()(AbstractHeap heap) >+ void operator()(AbstractHeap heap) const > { > m_value.read(heap); > } >@@ -972,7 +974,7 @@ public: > { > } > >- void operator()(AbstractHeap heap) >+ void operator()(AbstractHeap heap) const > { > m_value.write(heap); > } >@@ -988,12 +990,12 @@ public: > { > } > >- void operator()(PureValue value) >+ void operator()(PureValue value) const > { > m_value.def(value); > } > >- void operator()(HeapLocation location, Node* node) >+ void operator()(HeapLocation location, Node* node) const > { > m_value.def(location, node); > } >Index: Source/JavaScriptCore/dfg/DFGCriticalEdgeBreakingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCriticalEdgeBreakingPhase.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGCriticalEdgeBreakingPhase.cpp (working copy) >@@ -77,7 +77,7 @@ private: > // don't know its execution frequency. > BasicBlock* pad = m_insertionSet.insertBefore(*successor, PNaN); > pad->appendNode( >- m_graph, SpecNone, Jump, (*successor)->at(0)->origin, OpInfo(*successor)); >+ m_graph, SpecNone, Jump, (*successor)->firstOrigin(), OpInfo(*successor)); > pad->predecessors.append(predecessor); > (*successor)->replacePredecessor(predecessor, pad); > >Index: Source/JavaScriptCore/dfg/DFGDoesGC.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGDoesGC.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGDoesGC.cpp (working copy) >@@ -203,6 +203,8 @@ bool doesGC(Graph& graph, Node* node) > case PutByOffsetHint: > case CheckStructureImmediate: > case PutStructureHint: >+ case PutLocal: >+ case KillLocal: > return false; > > case CreateActivation: >Index: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (working copy) >@@ -1018,6 +1018,8 @@ private: > case CheckStructureImmediate: > case PutStructureHint: > case MaterializeNewObject: >+ case PutLocal: >+ case KillLocal: > // These are just nodes that we don't currently expect to see during fixup. > // If we ever wanted to insert them prior to fixup, then we just have to create > // fixup rules for them. >Index: Source/JavaScriptCore/dfg/DFGFlushFormat.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFlushFormat.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGFlushFormat.h (working copy) >@@ -118,6 +118,17 @@ inline DataFormat dataFormatFor(FlushFor > return DataFormatDead; > } > >+inline FlushFormat merge(FlushFormat a, FlushFormat b) >+{ >+ if (a == DeadFlush) >+ return b; >+ if (b == DeadFlush) >+ return a; >+ if (a == b) >+ return a; >+ return ConflictingFlush; >+} >+ > } } // namespace JSC::DFG > > namespace WTF { >Index: Source/JavaScriptCore/dfg/DFGGraph.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGGraph.cpp (working copy) >@@ -75,6 +75,11 @@ Graph::Graph(VM& vm, Plan& plan, LongLiv > > for (unsigned i = m_mustHandleValues.size(); i--;) > m_mustHandleValues[i] = freezeFragile(plan.mustHandleValues[i]); >+ >+ for (unsigned i = m_codeBlock->m_numVars; i--;) { >+ if (m_codeBlock->isCaptured(virtualRegisterForLocal(i))) >+ m_outermostCapturedVars.set(i); >+ } > } > > Graph::~Graph() >Index: Source/JavaScriptCore/dfg/DFGGraph.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGGraph.h (working copy) >@@ -367,6 +367,13 @@ public: > return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock); > } > >+ const BitVector& capturedVarsFor(InlineCallFrame* inlineCallFrame) >+ { >+ if (!inlineCallFrame) >+ return m_outermostCapturedVars; >+ return inlineCallFrame->capturedVars; >+ } >+ > bool isStrictModeFor(CodeOrigin codeOrigin) > { > if (!codeOrigin.inlineCallFrame) >@@ -888,6 +895,7 @@ public: > unsigned m_parameterSlots; > int m_machineCaptureStart; > std::unique_ptr<SlowArgument[]> m_slowArguments; >+ BitVector m_outermostCapturedVars; > > #if USE(JSVALUE32_64) > std::unordered_map<int64_t, double*> m_doubleConstantsMap; >Index: Source/JavaScriptCore/dfg/DFGLoopPreHeaderCreationPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGLoopPreHeaderCreationPhase.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGLoopPreHeaderCreationPhase.cpp (working copy) >@@ -42,7 +42,7 @@ BasicBlock* createPreHeader(Graph& graph > // Don't bother to preserve execution frequencies for now. > BasicBlock* preHeader = insertionSet.insertBefore(block, PNaN); > preHeader->appendNode( >- graph, SpecNone, Jump, block->at(0)->origin, OpInfo(block)); >+ graph, SpecNone, Jump, block->firstOrigin(), OpInfo(block)); > > for (unsigned predecessorIndex = 0; predecessorIndex < block->predecessors.size(); predecessorIndex++) { > BasicBlock* predecessor = block->predecessors[predecessorIndex]; >Index: Source/JavaScriptCore/dfg/DFGNode.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNode.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGNode.cpp (working copy) >@@ -79,6 +79,7 @@ bool Node::hasVariableAccessData(Graph& > case SetArgument: > case Flush: > case PhantomLocal: >+ case PutLocal: > return true; > default: > return false; >Index: Source/JavaScriptCore/dfg/DFGNode.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNode.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGNode.h (working copy) >@@ -683,6 +683,7 @@ struct Node { > case ExtractOSREntryLocal: > case MovHint: > case ZombieHint: >+ case KillLocal: > return true; > default: > return false; >@@ -1390,6 +1391,8 @@ struct Node { > { > switch (op()) { > case SetLocal: >+ case PutLocal: >+ case KillLocal: > case MovHint: > case ZombieHint: > case PhantomArguments: >Index: Source/JavaScriptCore/dfg/DFGNodeOrigin.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNodeOrigin.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGNodeOrigin.h (working copy) >@@ -49,6 +49,7 @@ struct NodeOrigin { > > bool isSet() const > { >+ ASSERT(semantic.isSet() == forExit.isSet()); > return semantic.isSet(); > } > >Index: Source/JavaScriptCore/dfg/DFGNodeType.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNodeType.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGNodeType.h (working copy) >@@ -56,6 +56,8 @@ namespace JSC { namespace DFG { > /* VariableAccessData, and thus will share predictions. */\ > macro(GetLocal, NodeResultJS) \ > macro(SetLocal, 0) \ >+ macro(PutLocal, NodeMustGenerate) \ >+ macro(KillLocal, NodeMustGenerate) \ > macro(MovHint, 0) \ > macro(ZombieHint, 0) \ > macro(GetArgument, NodeResultJS | NodeMustGenerate) \ >Index: Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp (working copy) >@@ -127,10 +127,14 @@ void LocalOSRAvailabilityCalculator::end > void LocalOSRAvailabilityCalculator::executeNode(Node* node) > { > switch (node->op()) { >- case SetLocal: { >+ case PutLocal: { > VariableAccessData* variable = node->variableAccessData(); >- m_availability.m_locals.operand(variable->local()) = >- Availability(node->child1().node(), variable->flushedAt()); >+ m_availability.m_locals.operand(variable->local()).setFlush(variable->flushedAt()); >+ break; >+ } >+ >+ case KillLocal: { >+ m_availability.m_locals.operand(node->unlinkedLocal()).setFlush(FlushedAt(ConflictingFlush)); > break; > } > >@@ -142,14 +146,12 @@ void LocalOSRAvailabilityCalculator::exe > } > > case MovHint: { >- m_availability.m_locals.operand(node->unlinkedLocal()) = >- Availability(node->child1().node()); >+ m_availability.m_locals.operand(node->unlinkedLocal()).setNode(node->child1().node()); > break; > } > > case ZombieHint: { >- m_availability.m_locals.operand(node->unlinkedLocal()) = >- Availability::unavailable(); >+ m_availability.m_locals.operand(node->unlinkedLocal()).setNodeUnavailable(); > break; > } > >Index: Source/JavaScriptCore/dfg/DFGPlan.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPlan.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGPlan.cpp (working copy) >@@ -54,6 +54,7 @@ > #include "DFGPhantomRemovalPhase.h" > #include "DFGPredictionInjectionPhase.h" > #include "DFGPredictionPropagationPhase.h" >+#include "DFGPutLocalSinkingPhase.h" > #include "DFGResurrectionForValidationPhase.h" > #include "DFGSSAConversionPhase.h" > #include "DFGSSALoweringPhase.h" >@@ -322,6 +323,7 @@ Plan::CompilationPath Plan::compileInThr > performCPSRethreading(dfg); > performSSAConversion(dfg); > performSSALowering(dfg); >+ performPutLocalSinking(dfg); > performGlobalCSE(dfg); > performLivenessAnalysis(dfg); > performCFA(dfg); >@@ -329,8 +331,10 @@ Plan::CompilationPath Plan::compileInThr > performPhantomCanonicalization(dfg); // Reduce the graph size a lot. > changed = false; > changed |= performStrengthReduction(dfg); >- changed |= performCriticalEdgeBreaking(dfg); >- changed |= performObjectAllocationSinking(dfg); >+ if (Options::enableObjectAllocationSinking()) { >+ changed |= performCriticalEdgeBreaking(dfg); >+ changed |= performObjectAllocationSinking(dfg); >+ } > if (changed) { > // State-at-tail and state-at-head will be invalid if we did strength reduction since > // it might increase live ranges. >@@ -353,7 +357,7 @@ Plan::CompilationPath Plan::compileInThr > performCFA(dfg); > if (Options::validateFTLOSRExitLiveness()) > performResurrectionForValidation(dfg); >- performDCE(dfg); // We rely on this to convert dead SetLocals into the appropriate hint, and to kill dead code that won't be recognized as dead by LLVM. >+ performDCE(dfg); // We rely on this to kill dead code that won't be recognized as dead by LLVM. > performStackLayout(dfg); > performLivenessAnalysis(dfg); > performOSRAvailabilityAnalysis(dfg); >Index: Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h (revision 0) >+++ Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h (working copy) >@@ -0,0 +1,163 @@ >+/* >+ * Copyright (C) 2014 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#ifndef DFGPreciseLocalClobberize_h >+#define DFGPreciseLocalClobberize_h >+ >+#if ENABLE(DFG_JIT) >+ >+#include "DFGClobberize.h" >+ >+namespace JSC { namespace DFG { >+ >+template<typename ReadFunctor, typename WriteFunctor, typename DefFunctor> >+class PreciseLocalClobberizeAdaptor { >+public: >+ PreciseLocalClobberizeAdaptor( >+ Graph& graph, Node* node, >+ const ReadFunctor& read, const WriteFunctor& write, const DefFunctor& def) >+ : m_graph(graph) >+ , m_node(node) >+ , m_read(read) >+ , m_write(write) >+ , m_def(def) >+ { >+ } >+ >+ void read(AbstractHeap heap) >+ { >+ if (heap.kind() == Variables) { >+ if (heap.payload().isTop()) { >+ readTop(); >+ return; >+ } >+ >+ m_read(VirtualRegister(heap.payload().value())); >+ return; >+ } >+ >+ if (heap.overlaps(Variables)) { >+ readTop(); >+ return; >+ } >+ } >+ >+ void write(AbstractHeap heap) >+ { >+ if (heap.kind() == Variables) { >+ if (heap.payload().isTop()) { >+ writeTop(); >+ return; >+ } >+ >+ m_write(VirtualRegister(heap.payload().value())); >+ return; >+ } >+ >+ if (heap.overlaps(Variables)) { >+ writeTop(); >+ return; >+ } >+ } >+ >+ void def(PureValue) >+ { >+ // PureValue defs never have anything to do with locals, so ignore this. >+ } >+ >+ void def(HeapLocation location, Node* node) >+ { >+ if (location.kind() != VariableLoc) >+ return; >+ >+ RELEASE_ASSERT(location.heap().kind() == Variables); >+ >+ m_def(VirtualRegister(location.heap().payload().value()), node); >+ } >+ >+private: >+ void readTop() >+ { >+ // All of the outermost arguments, except this, are definitely read. >+ for (unsigned i = m_graph.m_codeBlock->numParameters(); i-- > 1;) >+ m_read(virtualRegisterForArgument(i)); >+ >+ // The stack header is read. >+ for (unsigned i = 0; i < JSStack::ThisArgument; ++i) >+ m_read(VirtualRegister(i)); >+ >+ // Read all of the captured variables. >+ const BitVector& capturedVars = >+ m_graph.capturedVarsFor(m_node->origin.semantic.inlineCallFrame); >+ for (unsigned i : capturedVars.setBits()) >+ m_read(virtualRegisterForLocal(i)); >+ >+ // Read all of the inline arguments and call frame headers that we didn't already capture. >+ for (InlineCallFrame* inlineCallFrame = m_node->origin.semantic.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->caller.inlineCallFrame) { >+ for (unsigned i = inlineCallFrame->arguments.size(); i-- > 1;) >+ m_read(VirtualRegister(inlineCallFrame->stackOffset + virtualRegisterForArgument(i).offset())); >+ if (inlineCallFrame->isClosureCall) { >+ m_read(VirtualRegister(inlineCallFrame->stackOffset + JSStack::ScopeChain)); >+ m_read(VirtualRegister(inlineCallFrame->stackOffset + JSStack::Callee)); >+ } >+ } >+ } >+ >+ void writeTop() >+ { >+ if (m_graph.m_codeBlock->usesArguments()) { >+ for (unsigned i = m_graph.m_codeBlock->numParameters(); i-- > 1;) >+ m_write(virtualRegisterForArgument(i)); >+ } >+ >+ const BitVector& capturedVars = >+ m_graph.capturedVarsFor(m_node->origin.semantic.inlineCallFrame); >+ for (unsigned i : capturedVars.setBits()) >+ m_write(virtualRegisterForLocal(i)); >+ } >+ >+ Graph& m_graph; >+ Node* m_node; >+ const ReadFunctor& m_read; >+ const WriteFunctor& m_write; >+ const DefFunctor& m_def; >+}; >+ >+template<typename ReadFunctor, typename WriteFunctor, typename DefFunctor> >+void preciseLocalClobberize( >+ Graph& graph, Node* node, >+ const ReadFunctor& read, const WriteFunctor& write, const DefFunctor& def) >+{ >+ PreciseLocalClobberizeAdaptor<ReadFunctor, WriteFunctor, DefFunctor> >+ adaptor(graph, node, read, write, def); >+ clobberize(graph, node, adaptor); >+} >+ >+} } // namespace JSC::DFG >+ >+#endif // ENABLE(DFG_JIT) >+ >+#endif // DFGPreciseLocalClobberize_h >+ >Index: Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (working copy) >@@ -565,7 +565,9 @@ private: > case PutByOffsetHint: > case CheckStructureImmediate: > case PutStructureHint: >- case MaterializeNewObject: { >+ case MaterializeNewObject: >+ case PutLocal: >+ case KillLocal: { > // This node should never be visible at this stage of compilation. It is > // inserted by fixup(), which follows this phase. > RELEASE_ASSERT_NOT_REACHED(); >Index: Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp (revision 0) >+++ Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp (working copy) >@@ -0,0 +1,467 @@ >+/* >+ * Copyright (C) 2014 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "DFGPutLocalSinkingPhase.h" >+ >+#if ENABLE(DFG_JIT) >+ >+#include "DFGBlockMapInlines.h" >+#include "DFGGraph.h" >+#include "DFGInsertionSet.h" >+#include "DFGPhase.h" >+#include "DFGPreciseLocalClobberize.h" >+#include "DFGSSACalculator.h" >+#include "DFGValidate.h" >+#include "JSCInlines.h" >+#include "OperandsInlines.h" >+ >+namespace JSC { namespace DFG { >+ >+namespace { >+ >+bool verbose = false; >+ >+class VariableDeferral { >+public: >+ VariableDeferral(VariableAccessData* variable = nullptr) >+ : m_variable(variable) >+ { >+ } >+ >+ static VariableDeferral conflict() >+ { >+ return VariableDeferral(conflictMarker()); >+ } >+ >+ bool operator!() const { return !m_variable; } >+ >+ bool hasVariable() const { return !!*this && !isConflict(); } >+ >+ VariableAccessData* variable() const >+ { >+ ASSERT(hasVariable()); >+ return m_variable; >+ } >+ >+ bool isConflict() const >+ { >+ return m_variable == conflictMarker(); >+ } >+ >+ VariableDeferral merge(VariableDeferral other) const >+ { >+ if (*this == other || !other) >+ return *this; >+ if (!*this) >+ return other; >+ return conflict(); >+ } >+ >+ bool operator==(VariableDeferral other) const >+ { >+ return m_variable == other.m_variable; >+ } >+ >+ void dump(PrintStream& out) const >+ { >+ if (!*this) >+ out.print("-"); >+ else if (isConflict()) >+ out.print("Conflict"); >+ else >+ out.print(RawPointer(m_variable)); >+ } >+ >+ void dumpInContext(PrintStream& out, DumpContext*) const >+ { >+ dump(out); >+ } >+ >+private: >+ static VariableAccessData* conflictMarker() >+ { >+ return bitwise_cast<VariableAccessData*>(static_cast<intptr_t>(1)); >+ } >+ >+ VariableAccessData* m_variable; >+}; >+ >+class PutLocalSinkingPhase : public Phase { >+public: >+ PutLocalSinkingPhase(Graph& graph) >+ : Phase(graph, "PutLocal sinking") >+ { >+ } >+ >+ bool run() >+ { >+ // FIXME: One of the problems of this approach is that it will create a duplicate Phi graph >+ // for sunken PutLocals in the presence of interesting control flow merges, and where the >+ // value being PutLocal'd is also otherwise live in the DFG code. We could work around this >+ // by doing the sinking over CPS, or maybe just by doing really smart hoisting. It's also >+ // possible that the duplicate Phi graph can be deduplicated by LLVM. It would be best if we >+ // could observe that there is already a Phi graph in place that does what we want. In >+ // principle if we have a request to place a Phi at a particular place, we could just check >+ // if there is already a Phi that does what we want. Because PutLocalSinkingPhase runs just >+ // after SSA conversion, we have almost a guarantee that the Phi graph we produce here would >+ // be trivially redundant to the one we already have. >+ >+ if (verbose) { >+ dataLog("Graph before PutLocal sinking:\n"); >+ m_graph.dump(); >+ } >+ >+ SSACalculator ssaCalculator(m_graph); >+ InsertionSet insertionSet(m_graph); >+ >+ // First figure out where various locals are live. >+ BlockMap<Operands<bool>> liveAtHead(m_graph); >+ BlockMap<Operands<bool>> liveAtTail(m_graph); >+ >+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >+ liveAtHead[block] = Operands<bool>(OperandsLike, block->variablesAtHead); >+ liveAtTail[block] = Operands<bool>(OperandsLike, block->variablesAtHead); >+ >+ liveAtHead[block].fill(false); >+ liveAtTail[block].fill(false); >+ } >+ >+ bool changed; >+ do { >+ changed = false; >+ >+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { >+ BasicBlock* block = m_graph.block(blockIndex); >+ if (!block) >+ continue; >+ >+ Operands<bool> live = liveAtTail[block]; >+ for (unsigned nodeIndex = block->size(); nodeIndex--;) { >+ Node* node = block->at(nodeIndex); >+ if (verbose) >+ dataLog("Live at ", node, ": ", live, "\n"); >+ >+ auto escapeHandler = [&] (VirtualRegister operand) { >+ if (operand.isHeader()) >+ return; >+ if (verbose) >+ dataLog(" r", operand, " is live at ", node ,"\n"); >+ live.operand(operand) = true; >+ }; >+ >+ preciseLocalClobberize( >+ m_graph, node, escapeHandler, escapeHandler, >+ [&] (VirtualRegister operand, Node* source) { >+ if (source == node) { >+ // This is a load. Ignore it. >+ return; >+ } >+ >+ RELEASE_ASSERT(node->op() == PutLocal); >+ live.operand(operand) = false; >+ }); >+ } >+ >+ if (live == liveAtHead[block]) >+ continue; >+ >+ liveAtHead[block] = live; >+ changed = true; >+ >+ for (BasicBlock* predecessor : block->predecessors) { >+ for (size_t i = live.size(); i--;) >+ liveAtTail[predecessor][i] |= live[i]; >+ } >+ } >+ >+ } while (changed); >+ >+ // All of the locals should be dead at head of root. All of the arguments should be live at >+ // head of root. >+ for (size_t i = liveAtHead.atIndex(0).numberOfLocals(); i--;) >+ DFG_ASSERT(m_graph, nullptr, !liveAtHead.atIndex(0).local(i)); >+ for (size_t i = liveAtHead.atIndex(0).numberOfArguments(); i--;) >+ DFG_ASSERT(m_graph, nullptr, liveAtHead.atIndex(0).argument(i)); >+ >+ // Next identify where we would want to sink PutLocals to. We say that there is a deferred >+ // flush if we had a PutLocal with a given VariableAccessData* but it hasn't been >+ // materialized yet. >+ BlockMap<Operands<VariableDeferral>> deferredAtHead(m_graph); >+ BlockMap<Operands<VariableDeferral>> deferredAtTail(m_graph); >+ >+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >+ deferredAtHead[block] = >+ Operands<VariableDeferral>(OperandsLike, block->variablesAtHead); >+ deferredAtTail[block] = >+ Operands<VariableDeferral>(OperandsLike, block->variablesAtHead); >+ } >+ >+ do { >+ changed = false; >+ >+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >+ Operands<VariableDeferral> deferred = deferredAtHead[block]; >+ >+ for (Node* node : *block) { >+ if (verbose) >+ dataLog("Deferred at ", node, ":", deferred, "\n"); >+ >+ auto escapeHandler = [&] (VirtualRegister operand) { >+ if (operand.isHeader()) >+ return; >+ // We will materialize just before any reads. >+ deferred.operand(operand) = VariableDeferral(); >+ }; >+ >+ preciseLocalClobberize( >+ m_graph, node, escapeHandler, escapeHandler, >+ [&] (VirtualRegister operand, Node* source) { >+ if (source == node) { >+ // This is a load. Ignore it. >+ return; >+ } >+ >+ deferred.operand(operand) = VariableDeferral(node->variableAccessData()); >+ }); >+ } >+ >+ if (deferred == deferredAtTail[block]) >+ continue; >+ >+ deferredAtTail[block] = deferred; >+ changed = true; >+ >+ for (BasicBlock* successor : block->successors()) { >+ for (size_t i = deferred.size(); i--;) { >+ if (verbose) >+ dataLog("Considering r", deferred.operandForIndex(i), " at ", pointerDump(block), "->", pointerDump(successor), ": "); >+ >+ deferredAtHead[successor][i] = >+ deferredAtHead[successor][i].merge(deferred[i]); >+ >+ if (verbose) >+ dataLog(deferredAtHead[successor][i], "\n"); >+ } >+ } >+ } >+ >+ } while (changed); >+ >+ // We wish to insert PutLocals at all of the materialization points, which are defined >+ // implicitly as the places where we set deferred to Dead while it was previously not Dead. >+ // To do this, we may need to build some Phi functions to handle stuff like this: >+ // >+ // Before: >+ // >+ // if (p) >+ // PutLocal(r42, @x) >+ // else >+ // PutLocal(r42, @y) >+ // >+ // After: >+ // >+ // if (p) >+ // Upsilon(@x, ^z) >+ // else >+ // Upsilon(@y, ^z) >+ // z: Phi() >+ // PutLocal(r42, @z) >+ // >+ // This means that we have an SSACalculator::Variable for each local, and a Def is any >+ // PutLocal in the original program. The original PutLocals will simply vanish. >+ >+ Operands<SSACalculator::Variable*> operandToVariable( >+ OperandsLike, m_graph.block(0)->variablesAtHead); >+ Vector<VirtualRegister> indexToOperand; >+ for (size_t i = m_graph.block(0)->variablesAtHead.size(); i--;) { >+ VirtualRegister operand(m_graph.block(0)->variablesAtHead.operandForIndex(i)); >+ >+ SSACalculator::Variable* variable = ssaCalculator.newVariable(); >+ operandToVariable.operand(operand) = variable; >+ ASSERT(indexToOperand.size() == variable->index()); >+ indexToOperand.append(operand); >+ } >+ >+ HashSet<Node*> putLocalsToSink; >+ >+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >+ for (Node* node : *block) { >+ if (node->op() != PutLocal) >+ continue; >+ >+ putLocalsToSink.add(node); >+ ssaCalculator.newDef( >+ operandToVariable.operand(node->local()), block, node->child1().node()); >+ } >+ } >+ >+ ssaCalculator.computePhis( >+ [&] (SSACalculator::Variable* variable, BasicBlock* block) -> Node* { >+ VirtualRegister operand = indexToOperand[variable->index()]; >+ >+ if (!liveAtHead[block].operand(operand)) >+ return nullptr; >+ >+ if (verbose) >+ dataLog("Adding Phi for r", operand, " at ", pointerDump(block), "\n"); >+ >+ Node* phiNode = m_graph.addNode(SpecHeapTop, Phi, NodeOrigin()); >+ VariableDeferral variableDeferral = deferredAtHead[block].operand(operand); >+ // If it's live in bytecode then we must have a valid deferral. >+ DFG_ASSERT(m_graph, nullptr, variableDeferral.hasVariable()); >+ FlushFormat format = variableDeferral.variable()->flushFormat(); >+ phiNode->mergeFlags(resultFor(format)); >+ return phiNode; >+ }); >+ >+ Operands<Node*> mapping(OperandsLike, m_graph.block(0)->variablesAtHead); >+ Operands<VariableDeferral> deferred; >+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >+ mapping.fill(nullptr); >+ >+ for (size_t i = mapping.size(); i--;) { >+ VirtualRegister operand(mapping.operandForIndex(i)); >+ >+ SSACalculator::Variable* variable = operandToVariable.operand(operand); >+ SSACalculator::Def* def = ssaCalculator.reachingDefAtHead(block, variable); >+ if (!def) >+ continue; >+ >+ mapping.operand(operand) = def->value(); >+ } >+ >+ for (SSACalculator::Def* phiDef : ssaCalculator.phisForBlock(block)) { >+ VirtualRegister operand = indexToOperand[phiDef->variable()->index()]; >+ >+ insertionSet.insert(0, phiDef->value()); >+ >+ mapping.operand(operand) = phiDef->value(); >+ } >+ >+ deferred = deferredAtHead[block]; >+ for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { >+ Node* node = block->at(nodeIndex); >+ if (verbose) >+ dataLog("Deferred at ", node, ":", deferred, "\n"); >+ >+ if (node->op() == PutLocal) { >+ VariableAccessData* variable = node->variableAccessData(); >+ VirtualRegister operand = variable->local(); >+ deferred.operand(operand) = VariableDeferral(variable); >+ mapping.operand(operand) = node->child1().node(); >+ continue; >+ } >+ >+ auto escapeHandler = [&] (VirtualRegister operand) { >+ if (operand.isHeader()) >+ return; >+ >+ if (!deferred.operand(operand)) >+ return; >+ >+ Node* incoming = mapping.operand(operand); >+ DFG_ASSERT(m_graph, node, incoming); >+ >+ // Gotta insert a PutLocal. >+ if (verbose) >+ dataLog("Inserting a PutLocal for r", operand, " at ", node, "\n"); >+ VariableDeferral variableDeferral = deferred.operand(operand); >+ DFG_ASSERT(m_graph, node, variableDeferral.hasVariable()); >+ insertionSet.insertNode( >+ nodeIndex, SpecNone, PutLocal, node->origin, >+ OpInfo(variableDeferral.variable()), >+ Edge(incoming, useKindFor(variableDeferral.variable()->flushFormat()))); >+ >+ deferred.operand(operand) = nullptr; >+ }; >+ >+ preciseLocalClobberize( >+ m_graph, node, escapeHandler, escapeHandler, >+ [&] (VirtualRegister, Node*) { }); >+ } >+ >+ size_t upsilonInsertionPoint = block->size() - 1; >+ NodeOrigin upsilonOrigin = block->last()->origin; >+ for (BasicBlock* successorBlock : block->successors()) { >+ for (SSACalculator::Def* phiDef : ssaCalculator.phisForBlock(successorBlock)) { >+ Node* phiNode = phiDef->value(); >+ SSACalculator::Variable* variable = phiDef->variable(); >+ VirtualRegister operand = indexToOperand[variable->index()]; >+ VariableDeferral variableDeferral = >+ deferredAtHead[successorBlock].operand(operand); >+ DFG_ASSERT(m_graph, nullptr, variableDeferral.hasVariable()); >+ FlushFormat format = variableDeferral.variable()->flushFormat(); >+ UseKind useKind = useKindFor(format); >+ Node* incoming = mapping.operand(operand); >+ >+ insertionSet.insertNode( >+ upsilonInsertionPoint, SpecNone, Upsilon, upsilonOrigin, >+ OpInfo(phiNode), Edge(incoming, useKind)); >+ } >+ } >+ >+ insertionSet.execute(block); >+ } >+ >+ // Finally eliminate the sunken PutLocals by turning them into Phantoms. This keeps whatever >+ // type check they were doing. Also prepend KillLocals to them to ensure that we know that >+ // the relevant value was *not* stored to the stack. >+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >+ for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { >+ Node* node = block->at(nodeIndex); >+ >+ if (!putLocalsToSink.contains(node)) >+ continue; >+ >+ insertionSet.insertNode( >+ nodeIndex, SpecNone, KillLocal, node->origin, OpInfo(node->local().offset())); >+ node->convertToPhantom(); >+ } >+ >+ insertionSet.execute(block); >+ } >+ >+ if (verbose) { >+ dataLog("Graph after PutLocal sinking:\n"); >+ m_graph.dump(); >+ } >+ >+ return true; >+ } >+}; >+ >+} // anonymous namespace >+ >+bool performPutLocalSinking(Graph& graph) >+{ >+ SamplingRegion samplingRegion("DFG PutLocal Sinking Phase"); >+ return runPhase<PutLocalSinkingPhase>(graph); >+} >+ >+} } // namespace JSC::DFG >+ >+#endif // ENABLE(DFG_JIT) >+ >Index: Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h (revision 0) >+++ Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h (working copy) >@@ -0,0 +1,46 @@ >+ /* >+ * Copyright (C) 2014 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#ifndef DFGPutLocalSinkingPhase_h >+#define DFGPutLocalSinkingPhase_h >+ >+#if ENABLE(DFG_JIT) >+ >+namespace JSC { namespace DFG { >+ >+class Graph; >+ >+// Sinks PutLocals to the absolute latest point where they can possibly happen, which is usually >+// side-effects that may observe them. This eliminates PutLocals if it sinks them past the point of >+// their deaths. >+ >+bool performPutLocalSinking(Graph&); >+ >+} } // namespace JSC::DFG >+ >+#endif // ENABLE(DFG_JIT) >+ >+#endif // DFGPutLocalSinkingPhase_h >+ >Index: Source/JavaScriptCore/dfg/DFGSSACalculator.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSSACalculator.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGSSACalculator.h (working copy) >@@ -174,7 +174,7 @@ public: > // nonLocalReachingDef() will find it later. Note that it is generally always sound to not > // prune any Phis (that is, to always have the functor insert a Phi and never return nullptr). > template<typename PhiInsertionFunctor> >- void computePhis(PhiInsertionFunctor functor) >+ void computePhis(const PhiInsertionFunctor& functor) > { > DFG_ASSERT(m_graph, nullptr, m_graph.m_dominators.isValid()); > >Index: Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp (working copy) >@@ -184,12 +184,14 @@ public: > // - Convert all of the preexisting SSA nodes (other than the old CPS Phi nodes) into SSA > // form by replacing as follows: > // >+ // - MovHint has KillLocal prepended to it. >+ // > // - GetLocal over captured variables lose their phis. > // > // - GetLocal over uncaptured variables die and get replaced with references to the node > // specified by valueForOperand. > // >- // - SetLocal gets NodeMustGenerate if it's flushed, or turns into a Check otherwise. >+ // - SetLocal turns into PutLocal if it's flushed, or turns into a Check otherwise. > // > // - Flush loses its children and turns into a Phantom. > // >@@ -249,41 +251,12 @@ public: > for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(block)) { > VariableAccessData* variable = m_variableForSSAIndex[phiDef->variable()->index()]; > >- // Figure out if the local is meant to be flushed here. >- bool isFlushed = !!( >- block->variablesAtHead.operand(variable->local())->flags() & NodeIsFlushed); >- > m_insertionSet.insert(phiInsertionPoint, phiDef->value()); > valueForOperand.operand(variable->local()) = phiDef->value(); > >- if (isFlushed) { >- // Do nothing. For multiple reasons. >- >- // Reason #1: If the local is flushed then we don't need to bother with a >- // MovHint since every path to this point in the code will have flushed the >- // bytecode variable using a SetLocal and hence the Availability::flushedAt() >- // will agree, and that will be sufficient for figuring out how to recover the >- // variable's value. >- >- // Reason #2: If we had inserted a MovHint and the Phi function had died >- // (because the only user of the value was the "flush" - i.e. some >- // asynchronous runtime thingy) then the MovHint would turn into a ZombieHint, >- // which would fool us into thinking that the variable is dead. Note that this >- // reason has a lot to do with the fact that Flushes do not turn into >- // Phantoms, because our handling of Flushes assume that we (1) always leave >- // the flushed SetLocals alone and (2) OSR availability analysis always sees >- // the available flush. The presence of a MovHint or ZombieHint would make the >- // flush seem unavailable. >- >- // Reason #3: If we had inserted a MovHint then even if the Phi stayed alive, >- // we would still end up generating inefficient code since we would be telling >- // the OSR exit compiler to use some SSA value for the bytecode variable >- // rather than just telling it that the value was already on the stack. >- } else { >- m_insertionSet.insertNode( >- phiInsertionPoint, SpecNone, MovHint, NodeOrigin(), >- OpInfo(variable->local().offset()), phiDef->value()->defaultEdge()); >- } >+ m_insertionSet.insertNode( >+ phiInsertionPoint, SpecNone, MovHint, NodeOrigin(), >+ OpInfo(variable->local().offset()), phiDef->value()->defaultEdge()); > } > > for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { >@@ -297,11 +270,18 @@ public: > m_graph.performSubstitution(node); > > switch (node->op()) { >+ case MovHint: { >+ m_insertionSet.insertNode( >+ nodeIndex, SpecNone, KillLocal, node->origin, >+ OpInfo(node->unlinkedLocal().offset())); >+ break; >+ } >+ > case SetLocal: { > VariableAccessData* variable = node->variableAccessData(); > > if (variable->isCaptured() || !!(node->flags() & NodeIsFlushed)) >- node->mergeFlags(NodeMustGenerate); >+ node->setOpAndDefaultFlags(PutLocal); > else > node->setOpAndDefaultFlags(Check); > >Index: Source/JavaScriptCore/dfg/DFGSafeToExecute.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSafeToExecute.h (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGSafeToExecute.h (working copy) >@@ -118,6 +118,8 @@ bool safeToExecute(AbstractStateType& st > case GetCallee: > case GetLocal: > case SetLocal: >+ case PutLocal: >+ case KillLocal: > case MovHint: > case ZombieHint: > case GetArgument: >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (working copy) >@@ -4987,6 +4987,8 @@ void SpeculativeJIT::compile(Node* node) > case CheckStructureImmediate: > case PutStructureHint: > case MaterializeNewObject: >+ case PutLocal: >+ case KillLocal: > DFG_CRASH(m_jit.graph(), node, "Unexpected node"); > break; > } >Index: Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp (working copy) >@@ -66,6 +66,7 @@ public: > switch (node->op()) { > case GetLocal: > case SetLocal: >+ case PutLocal: > case Flush: > case PhantomLocal: { > VariableAccessData* variable = node->variableAccessData(); >Index: Source/JavaScriptCore/dfg/DFGValidate.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGValidate.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGValidate.cpp (working copy) >@@ -74,7 +74,7 @@ public: > } while (0) > > #define notSet (static_cast<size_t>(-1)) >- >+ > void validate() > { > // NB. This code is not written for performance, since it is not intended to run >@@ -213,6 +213,9 @@ public: > case Identity: > VALIDATE((node), canonicalResultRepresentation(node->result()) == canonicalResultRepresentation(node->child1()->result())); > break; >+ case SetLocal: >+ VALIDATE((node), !!node->child1()); >+ break; > case MakeRope: > case ValueAdd: > case ArithAdd: >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 174031) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -47,6 +47,8 @@ inline CapabilityLevel canCompile(Node* > case GetMyArgumentsLength: > case GetLocal: > case SetLocal: >+ case PutLocal: >+ case KillLocal: > case MovHint: > case ZombieHint: > case Phantom: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 174031) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -386,8 +386,8 @@ private: > case GetLocal: > compileGetLocal(); > break; >- case SetLocal: >- compileSetLocal(); >+ case PutLocal: >+ compilePutLocal(); > break; > case GetMyArgumentsLength: > compileGetMyArgumentsLength(); >@@ -746,6 +746,7 @@ private: > case PutByOffsetHint: > case PutStructureHint: > case BottomValue: >+ case KillLocal: > break; > default: > DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend"); >@@ -1024,7 +1025,7 @@ private: > setJSValue(m_out.load64(addressFor(variable->machineLocal()))); > } > >- void compileSetLocal() >+ void compilePutLocal() > { > VariableAccessData* variable = m_node->variableAccessData(); > switch (variable->flushFormat()) { >Index: Source/JavaScriptCore/runtime/Options.h >=================================================================== >--- Source/JavaScriptCore/runtime/Options.h (revision 174031) >+++ Source/JavaScriptCore/runtime/Options.h (working copy) >@@ -176,6 +176,7 @@ typedef const char* optionString; > v(bool, enableCallEdgeProfiling, true) \ > v(unsigned, frequentCallThreshold, 2) \ > v(bool, optimizeNativeCalls, false) \ >+ v(bool, enableObjectAllocationSinking, true) \ > \ > v(bool, enableConcurrentJIT, true) \ > v(unsigned, numberOfDFGCompilerThreads, computeNumberOfWorkerThreads(2, 2) - 1) \ >Index: Source/WTF/ChangeLog >=================================================================== >--- Source/WTF/ChangeLog (revision 174045) >+++ Source/WTF/ChangeLog (working copy) >@@ -1,3 +1,23 @@ >+2014-09-28 Filip Pizlo <fpizlo@apple.com> >+ >+ FTL should sink SetLocals >+ https://bugs.webkit.org/show_bug.cgi?id=137168 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Make the set bits of a BitVector iterable. >+ >+ * wtf/BitVector.h: >+ (WTF::BitVector::SetBitsIterable::SetBitsIterable): >+ (WTF::BitVector::SetBitsIterable::iterator::iterator): >+ (WTF::BitVector::SetBitsIterable::iterator::operator*): >+ (WTF::BitVector::SetBitsIterable::iterator::operator++): >+ (WTF::BitVector::SetBitsIterable::iterator::operator==): >+ (WTF::BitVector::SetBitsIterable::iterator::operator!=): >+ (WTF::BitVector::SetBitsIterable::begin): >+ (WTF::BitVector::SetBitsIterable::end): >+ (WTF::BitVector::setBits): >+ > 2014-09-26 Sam Weinig <sam@webkit.org> > > Replace OSObjectPtr with RetainPtr/adoptOS >Index: Source/WTF/wtf/BitVector.h >=================================================================== >--- Source/WTF/wtf/BitVector.h (revision 174031) >+++ Source/WTF/wtf/BitVector.h (working copy) >@@ -269,6 +269,58 @@ public: > return IntHash<uintptr_t>::hash(value); > } > >+ class SetBitsIterable { >+ public: >+ SetBitsIterable(const BitVector& bitVector) >+ : m_bitVector(bitVector) >+ { >+ } >+ >+ class iterator { >+ public: >+ iterator() >+ : m_bitVector(nullptr) >+ , m_index(0) >+ { >+ } >+ >+ iterator(const BitVector& bitVector, size_t index) >+ : m_bitVector(&bitVector) >+ , m_index(index) >+ { >+ } >+ >+ size_t operator*() const { return m_index; } >+ >+ iterator& operator++() >+ { >+ m_index = m_bitVector->findBit(m_index + 1, true); >+ return *this; >+ } >+ >+ bool operator==(const iterator& other) const >+ { >+ return m_index == other.m_index; >+ } >+ >+ bool operator!=(const iterator& other) const >+ { >+ return !(*this == other); >+ } >+ private: >+ const BitVector* m_bitVector; >+ size_t m_index; >+ }; >+ >+ iterator begin() const { return iterator(m_bitVector, m_bitVector.findBit(0, true)); } >+ iterator end() const { return iterator(m_bitVector, m_bitVector.size()); } >+ >+ private: >+ const BitVector& m_bitVector; >+ }; >+ >+ SetBitsIterable setBits() const { return SetBitsIterable(*this); } >+ > private: > static unsigned bitsInPointer() > { >Index: LayoutTests/js/regress/elidable-new-object-then-call-expected.txt >=================================================================== >--- LayoutTests/js/regress/elidable-new-object-then-call-expected.txt (revision 0) >+++ LayoutTests/js/regress/elidable-new-object-then-call-expected.txt (working copy) >@@ -0,0 +1,10 @@ >+JSRegress/elidable-new-object-then-call >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+ >+PASS no exception thrown >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >Index: LayoutTests/js/regress/elidable-new-object-then-call.html >=================================================================== >--- LayoutTests/js/regress/elidable-new-object-then-call.html (revision 0) >+++ LayoutTests/js/regress/elidable-new-object-then-call.html (working copy) >@@ -0,0 +1,12 @@ >+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<script src="../../resources/regress-pre.js"></script> >+<script src="script-tests/elidable-new-object-then-call.js"></script> >+<script src="../../resources/regress-post.js"></script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >Index: LayoutTests/js/regress/script-tests/elidable-new-object-then-call.js >=================================================================== >--- LayoutTests/js/regress/script-tests/elidable-new-object-then-call.js (revision 0) >+++ LayoutTests/js/regress/script-tests/elidable-new-object-then-call.js (working copy) >@@ -0,0 +1,28 @@ >+function sumOfArithSeries(limit) { >+ return limit * (limit + 1) / 2; >+} >+ >+var n = 10000000; >+ >+function bar(p, o) { >+ if (p) >+ return 5; >+ else >+ return 6; >+} >+ >+function foo() { >+ var result = 0; >+ for (var i = 0; i < n; ++i) { >+ var o = {f: i}; >+ var p = {f: i + 1}; >+ bar(i, o); >+ bar(i, p); >+ result += o.f + p.f; >+ } >+ return result; >+} >+ >+var result = foo(); >+if (result != sumOfArithSeries(n - 1) + sumOfArithSeries(n)) >+ throw "Error: bad result: " + result;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 137168
:
238816
|
238823
|
238826
|
238829
|
238903
|
238928
|
238983
|
238991
|
239169