WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
slightly different approach
blah.patch (text/plain), 56.42 KB, created by
Filip Pizlo
on 2014-09-30 17:41:39 PDT
(
hide
)
Description:
slightly different approach
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2014-09-30 17:41:39 PDT
Size:
56.42 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) >@@ -212,6 +212,7 @@ set(JavaScriptCore_SOURCES > dfg/DFGSSAConversionPhase.cpp > dfg/DFGSSALoweringPhase.cpp > dfg/DFGSafepoint.cpp >+ dfg/DFGSetLocalSinkingPhase.cpp > dfg/DFGSpeculativeJIT.cpp > dfg/DFGSpeculativeJIT32_64.cpp > dfg/DFGSpeculativeJIT64.cpp >Index: Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj >=================================================================== >--- Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (revision 174031) >+++ Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (working copy) >@@ -455,6 +455,7 @@ > <ClCompile Include="..\dfg\DFGPureValue.cpp" /> > <ClCompile Include="..\dfg\DFGResurrectionForValidationPhase.cpp" /> > <ClCompile Include="..\dfg\DFGSafepoint.cpp" /> >+ <ClCompile Include="..\dfg\DFGSetLocalSinkingPhase.cpp" /> > <ClCompile Include="..\dfg\DFGSpeculativeJIT.cpp" /> > <ClCompile Include="..\dfg\DFGSpeculativeJIT32_64.cpp" /> > <ClCompile Include="..\dfg\DFGSpeculativeJIT64.cpp" /> >@@ -1104,6 +1105,7 @@ > <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" /> >@@ -1118,6 +1120,7 @@ > <ClInclude Include="..\dfg\DFGScannable.h" /> > <ClInclude Include="..\dfg\DFGScoreBoard.h" /> > <ClInclude Include="..\dfg\DFGScratchRegisterAllocator.h" /> >+ <ClInclude Include="..\dfg\DFGSetLocalSinkingPhase.h" /> > <ClInclude Include="..\dfg\DFGSilentRegisterSavePlan.h" /> > <ClInclude Include="..\dfg\DFGSlowPathGenerator.h" /> > <ClInclude Include="..\dfg\DFGSpeculativeJIT.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, ); }; }; >+ DC00039419D8BE6F00023EB0 /* DFGSetLocalSinkingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC00039119D8BE6F00023EB0 /* DFGSetLocalSinkingPhase.cpp */; }; >+ DC00039519D8BE6F00023EB0 /* DFGSetLocalSinkingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = DC00039219D8BE6F00023EB0 /* DFGSetLocalSinkingPhase.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>"; }; >+ DC00039119D8BE6F00023EB0 /* DFGSetLocalSinkingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGSetLocalSinkingPhase.cpp; path = dfg/DFGSetLocalSinkingPhase.cpp; sourceTree = "<group>"; }; >+ DC00039219D8BE6F00023EB0 /* DFGSetLocalSinkingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSetLocalSinkingPhase.h; path = dfg/DFGSetLocalSinkingPhase.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 */, >@@ -4775,6 +4782,8 @@ > A741017E179DAF80002EB8BA /* DFGSaneStringGetByValSlowPathGenerator.h */, > 0F2FCCF618A60070001A27F8 /* DFGScannable.h */, > 86ECA3F9132DF25A002B2AD7 /* DFGScoreBoard.h */, >+ DC00039119D8BE6F00023EB0 /* DFGSetLocalSinkingPhase.cpp */, >+ DC00039219D8BE6F00023EB0 /* DFGSetLocalSinkingPhase.h */, > 0F1E3A65153A21DF000F9456 /* DFGSilentRegisterSavePlan.h */, > 0F1E3A501537C2CB000F9456 /* DFGSlowPathGenerator.h */, > 86EC9DC21328DF82002B2AD7 /* DFGSpeculativeJIT.cpp */, >@@ -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 */, >@@ -5907,6 +5917,7 @@ > 86ADD1460FDDEA980006EEC2 /* MacroAssemblerARMv7.h in Headers */, > 863B23E00FC6118900703AA4 /* MacroAssemblerCodeRef.h in Headers */, > 86C568E111A213EE0007F7F0 /* MacroAssemblerMIPS.h in Headers */, >+ DC00039519D8BE6F00023EB0 /* DFGSetLocalSinkingPhase.h in Headers */, > 86AE64A9135E5E1C00963012 /* MacroAssemblerSH4.h in Headers */, > 860161E40F3A83C100F84710 /* MacroAssemblerX86.h in Headers */, > 860161E50F3A83C100F84710 /* MacroAssemblerX86_64.h in Headers */, >@@ -7088,6 +7099,7 @@ > 0FF729B0166AD35C000F5BA3 /* ProfilerCompilationKind.cpp in Sources */, > 0FF729B1166AD35C000F5BA3 /* ProfilerCompiledBytecode.cpp in Sources */, > 0FF729B2166AD35C000F5BA3 /* ProfilerDatabase.cpp in Sources */, >+ DC00039419D8BE6F00023EB0 /* DFGSetLocalSinkingPhase.cpp in Sources */, > 0F190CAC189D82F6000AE5F0 /* ProfilerJettisonReason.cpp in Sources */, > 0FF729B3166AD35C000F5BA3 /* ProfilerOrigin.cpp in Sources */, > 0FF729B4166AD35C000F5BA3 /* ProfilerOriginStack.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/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() const >+{ >+ 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() const; >+ > 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: > // >@@ -899,7 +899,7 @@ class NoOpClobberize { > public: > NoOpClobberize() { } > template<typename... T> >- void operator()(T...) { } >+ void operator()(T...) const { } > }; > > class CheckClobberize { >@@ -910,12 +910,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 +928,7 @@ public: > { > } > >- void operator()(AbstractHeap otherHeap) >+ void operator()(AbstractHeap otherHeap) const > { > if (m_result) > return; >@@ -939,7 +939,7 @@ public: > > private: > AbstractHeap m_heap; >- bool m_result; >+ mutable bool m_result; > }; > > bool accessesOverlap(Graph&, Node*, AbstractHeap); >@@ -956,7 +956,7 @@ public: > { > } > >- void operator()(AbstractHeap heap) >+ void operator()(AbstractHeap heap) const > { > m_value.read(heap); > } >@@ -972,7 +972,7 @@ public: > { > } > >- void operator()(AbstractHeap heap) >+ void operator()(AbstractHeap heap) const > { > m_value.write(heap); > } >@@ -988,12 +988,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/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/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/DFGPlan.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPlan.cpp (revision 174031) >+++ Source/JavaScriptCore/dfg/DFGPlan.cpp (working copy) >@@ -57,6 +57,7 @@ > #include "DFGResurrectionForValidationPhase.h" > #include "DFGSSAConversionPhase.h" > #include "DFGSSALoweringPhase.h" >+#include "DFGSetLocalSinkingPhase.h" > #include "DFGStackLayoutPhase.h" > #include "DFGStaticExecutionCountEstimationPhase.h" > #include "DFGStoreBarrierElisionPhase.h" >@@ -322,6 +323,7 @@ Plan::CompilationPath Plan::compileInThr > performCPSRethreading(dfg); > performSSAConversion(dfg); > performSSALowering(dfg); >+ performSetLocalSinking(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. >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/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/DFGSetLocalSinkingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSetLocalSinkingPhase.cpp (revision 0) >+++ Source/JavaScriptCore/dfg/DFGSetLocalSinkingPhase.cpp (working copy) >@@ -0,0 +1,399 @@ >+/* >+ * 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 "DFGSetLocalSinkingPhase.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 = true; >+ >+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(PrintStrea& out) const >+ { >+ if (!*this) >+ out.print("-"); >+ else if (isConflict()) >+ out.print("Conflict"); >+ else >+ out.print(RawPointer(m_variable)); >+ } >+ >+ void dumpInContext(const PrintStream& out, DumpContext*) const >+ { >+ dump(out); >+ } >+ >+private: >+ static VariableAccessData* conflictMarker() >+ { >+ return bitwise_cast<VariableAccessData*>(static_cast<intptr_t>(1)); >+ } >+ >+ VariableAccessData* m_variable; >+}; >+ >+class SetLocalSinkingPhase : public Phase { >+public: >+ SetLocalSinkingPhase(Graph& graph) >+ : Phase(graph, "SetLocal sinking") >+ { >+ } >+ >+ bool run() >+ { >+ // FIXME: One of the problems of this approach is that it will create a duplicate Phi graph >+ // for sunken SetLocals in the presence of interesting control flow merges, and where the >+ // value being SetLocal'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 SetLocalSinkingPhase 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 SetLocal sinking:\n"); >+ m_graph.dump(); >+ } >+ >+ SSACalculator ssaCalculator(m_graph); >+ InsertionSet insertionSet(m_graph); >+ >+ // Next identify where we would want to sink SetLocals to. We say that there is a deferred >+ // flush if we had a SetLocal 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]); >+ >+ out.print(deferredAtHead[successor][i], "\n"); >+ } >+ } >+ } >+ >+ } while (changed); >+ >+ // We wish to insert SetLocals 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) >+ // SetLocal(r42, @x) >+ // else >+ // SetLocal(r42, @y) >+ // >+ // After: >+ // >+ // if (p) >+ // Upsilon(@x, ^z) >+ // else >+ // Upsilon(@y, ^z) >+ // z: Phi() >+ // SetLocal(r42, @z) >+ // >+ // This means that we have an SSACalculator::Variable for each local, and a Def is any >+ // SetLocal in the original program. The original SetLocals 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); >+ } >+ >+ Vector<Node*> setLocalsToSink; >+ >+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >+ for (Node* node : *block) { >+ if (node->op() != SetLocal) >+ continue; >+ >+ setLocalsToSink.append(node); >+ ssaCalculator.newDef( >+ operandToVariable.operand(node->local()), block, node->child1().node()); >+ } >+ } >+ >+ ssaCalculator.computePhis( >+ [&] (SSACalculator::Variable* variable, BasicBlock* block) -> Node* { >+ VirtualRegister operand = indexToOperand[variable->index()]; >+ >+ // Do pruning based on bytecode liveness. This subsumes the two notions of liveness >+ // that are relevant here: >+ // >+ // - We want to insert a Phi if there's a chance that someone would materialize the >+ // SetLocal at some point in the future. >+ // >+ // - We want to insert a Phi and a MovHint if the variable is live for OSR exit. >+ // >+ // Basically, the latter form of liveness - "live in bytecode" - subsumes the former. >+ if (!m_graph.isLiveInBytecode(operand, block->firstOrigin().forExit)) >+ 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()); >+ insertionSet.insertNode( >+ 0, SpecNone, MovHint, NodeOrigin(), OpInfo(operand.offset()), >+ phiDef->value()->defaultEdge()); >+ >+ 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() == SetLocal) { >+ 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 SetLocal. >+ if (verbose) >+ dataLog("Inserting a SetLocal for r", operand, " at ", node, "\n"); >+ VariableDeferral variableDeferral = deferred.operand(operand); >+ DFG_ASSERT(m_graph, node, variableDeferral.hasVariable()); >+ Node* setLocal = insertionSet.insertNode( >+ nodeIndex, SpecNone, SetLocal, node->origin, >+ OpInfo(variableDeferral.variable()), >+ Edge(incoming, useKindFor(variableAccessData->flushFormat()))); >+ // Man, this is awful. We shouldn't have to do this. >+ // https://bugs.webkit.org/show_bug.cgi?id=137242 >+ setLocal->mergeFlags(NodeMustGenerate); >+ >+ 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 SetLocals by turning them into Phantoms. This keeps whatever >+ // type check they were doing. >+ for (Node* node : setLocalsToSink) >+ node->convertToPhantom(); >+ >+ if (verbose) { >+ dataLog("Graph after SetLocal sinking:\n"); >+ m_graph.dump(); >+ } >+ >+ return true; >+ } >+}; >+ >+} // anonymous namespace >+ >+bool performSetLocalSinking(Graph& graph) >+{ >+ SamplingRegion samplingRegion("DFG SetLocal Sinking Phase"); >+ return runPhase<SetLocalSinkingPhase>(graph); >+} >+ >+} } // namespace JSC::DFG >+ >+#endif // ENABLE(DFG_JIT) >+ >Index: Source/JavaScriptCore/dfg/DFGSetLocalSinkingPhase.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSetLocalSinkingPhase.h (revision 0) >+++ Source/JavaScriptCore/dfg/DFGSetLocalSinkingPhase.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 DFGSetLocalSinkingPhase_h >+#define DFGSetLocalSinkingPhase_h >+ >+#if ENABLE(DFG_JIT) >+ >+namespace JSC { namespace DFG { >+ >+class Graph; >+ >+// Sinks SetLocals to the absolute latest point where they can possibly happen, which is usually >+// side-effects that may observe them. This eliminates SetLocals if it sinks them past the point of >+// their deaths. >+ >+bool performSetLocalSinking(Graph&); >+ >+} } // namespace JSC::DFG >+ >+#endif // ENABLE(DFG_JIT) >+ >+#endif // DFGSetLocalSinkingPhase_h >+ >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/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