Out-line ScratchRegisterAllocator
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 10 Mar 2014 20:58:29 +0000 (20:58 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 10 Mar 2014 20:58:29 +0000 (20:58 +0000)
Rubber stamped by Mark Hahnenberg.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGDriver.cpp:
(JSC::DFG::compileImpl):
* jit/ScratchRegisterAllocator.cpp: Added.
(JSC::ScratchRegisterAllocator::ScratchRegisterAllocator):
(JSC::ScratchRegisterAllocator::~ScratchRegisterAllocator):
(JSC::ScratchRegisterAllocator::lock):
(JSC::ScratchRegisterAllocator::allocateScratch):
(JSC::ScratchRegisterAllocator::allocateScratchGPR):
(JSC::ScratchRegisterAllocator::allocateScratchFPR):
(JSC::ScratchRegisterAllocator::preserveReusedRegistersByPushing):
(JSC::ScratchRegisterAllocator::restoreReusedRegistersByPopping):
(JSC::ScratchRegisterAllocator::desiredScratchBufferSize):
(JSC::ScratchRegisterAllocator::preserveUsedRegistersToScratchBuffer):
(JSC::ScratchRegisterAllocator::restoreUsedRegistersFromScratchBuffer):
* jit/ScratchRegisterAllocator.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@165401 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/dfg/DFGDriver.cpp
Source/JavaScriptCore/jit/ScratchRegisterAllocator.cpp [new file with mode: 0644]
Source/JavaScriptCore/jit/ScratchRegisterAllocator.h

index b86b364..0c20cdf 100644 (file)
@@ -302,6 +302,7 @@ set(JavaScriptCore_SOURCES
     jit/RegisterPreservationWrapperGenerator.cpp
     jit/RegisterSet.cpp
     jit/Repatch.cpp
+    jit/ScratchRegisterAllocator.cpp
     jit/TempRegisterSet.cpp
     jit/ThunkGenerators.cpp
 
index 3251902..cbaa0ed 100644 (file)
@@ -1,3 +1,29 @@
+2014-03-10  Filip Pizlo  <fpizlo@apple.com>
+
+        Out-line ScratchRegisterAllocator
+
+        Rubber stamped by Mark Hahnenberg.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * dfg/DFGDriver.cpp:
+        (JSC::DFG::compileImpl):
+        * jit/ScratchRegisterAllocator.cpp: Added.
+        (JSC::ScratchRegisterAllocator::ScratchRegisterAllocator):
+        (JSC::ScratchRegisterAllocator::~ScratchRegisterAllocator):
+        (JSC::ScratchRegisterAllocator::lock):
+        (JSC::ScratchRegisterAllocator::allocateScratch):
+        (JSC::ScratchRegisterAllocator::allocateScratchGPR):
+        (JSC::ScratchRegisterAllocator::allocateScratchFPR):
+        (JSC::ScratchRegisterAllocator::preserveReusedRegistersByPushing):
+        (JSC::ScratchRegisterAllocator::restoreReusedRegistersByPopping):
+        (JSC::ScratchRegisterAllocator::desiredScratchBufferSize):
+        (JSC::ScratchRegisterAllocator::preserveUsedRegistersToScratchBuffer):
+        (JSC::ScratchRegisterAllocator::restoreUsedRegistersFromScratchBuffer):
+        * jit/ScratchRegisterAllocator.h:
+
 2014-03-10  Brent Fulgham  <bfulgham@apple.com>
 
         [Win] Pass environment to Pre-Build, Pre-link, and Post-Build Stages.
index 8b04825..8dfb785 100644 (file)
@@ -817,6 +817,7 @@ javascriptcore_sources += \
        Source/JavaScriptCore/jit/Repatch.cpp \
        Source/JavaScriptCore/jit/Repatch.h \
        Source/JavaScriptCore/jit/ScratchRegisterAllocator.h \
+       Source/JavaScriptCore/jit/ScratchRegisterAllocator.cpp \
        Source/JavaScriptCore/jit/SlowPathCall.h \
        Source/JavaScriptCore/jit/SpecializedThunkJIT.h \
        Source/JavaScriptCore/jit/TempRegisterSet.cpp \
index edba320..b4c299c 100644 (file)
     <ClCompile Include="..\jit\Reg.cpp" />
     <ClCompile Include="..\jit\RegisterPreservationWrapperGenerator.cpp" />
     <ClCompile Include="..\jit\Repatch.cpp" />
+    <ClCompile Include="..\jit\ScratchRegisterAllocator.cpp" />
     <ClCompile Include="..\jit\ThunkGenerators.cpp" />
     <ClCompile Include="..\llint\LLIntCLoop.cpp" />
     <ClCompile Include="..\llint\LLIntData.cpp" />
index aa1634d..9c49578 100644 (file)
                0FA581BC150E953000B9A2D9 /* DFGNodeType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FA7A8EB18B413C80052371D /* Reg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FA7A8E918B413C80052371D /* Reg.cpp */; };
                0FA7A8EC18B413C80052371D /* Reg.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA7A8EA18B413C80052371D /* Reg.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FA7A8EE18CE4FD80052371D /* ScratchRegisterAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FA7A8ED18CE4FD80052371D /* ScratchRegisterAllocator.cpp */; };
                0FAF7EFD165BA91B000C8455 /* JITDisassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FAF7EFA165BA919000C8455 /* JITDisassembler.cpp */; };
                0FAF7EFE165BA91F000C8455 /* JITDisassembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FAF7EFB165BA919000C8455 /* JITDisassembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FB105851675480F00F8AB6E /* ExitKind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB105821675480C00F8AB6E /* ExitKind.cpp */; };
                0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGNodeType.h; path = dfg/DFGNodeType.h; sourceTree = "<group>"; };
                0FA7A8E918B413C80052371D /* Reg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Reg.cpp; sourceTree = "<group>"; };
                0FA7A8EA18B413C80052371D /* Reg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reg.h; sourceTree = "<group>"; };
+               0FA7A8ED18CE4FD80052371D /* ScratchRegisterAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScratchRegisterAllocator.cpp; sourceTree = "<group>"; };
                0FAF7EFA165BA919000C8455 /* JITDisassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITDisassembler.cpp; sourceTree = "<group>"; };
                0FAF7EFB165BA919000C8455 /* JITDisassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITDisassembler.h; sourceTree = "<group>"; };
                0FB105821675480C00F8AB6E /* ExitKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExitKind.cpp; sourceTree = "<group>"; };
                                0FC314101814559100033232 /* RegisterSet.h */,
                                0F24E54917EE274900ABB217 /* Repatch.cpp */,
                                0F24E54A17EE274900ABB217 /* Repatch.h */,
+                               0FA7A8ED18CE4FD80052371D /* ScratchRegisterAllocator.cpp */,
                                0F24E54B17EE274900ABB217 /* ScratchRegisterAllocator.h */,
                                A709F2EF17A0AC0400512E98 /* SlowPathCall.h */,
                                A7386551118697B400540279 /* SpecializedThunkJIT.h */,
+                               A7FF647A18C52E8500B55307 /* SpillRegistersMode.h */,
                                0FC314111814559100033232 /* TempRegisterSet.cpp */,
                                0F24E54817EE274900ABB217 /* TempRegisterSet.h */,
                                0F572D4D16879FDB00E57FBD /* ThunkGenerator.h */,
                                A7386552118697B400540279 /* ThunkGenerators.cpp */,
                                A7386553118697B400540279 /* ThunkGenerators.h */,
                                65987F2F16828A7E003C2F8D /* UnusedPointer.h */,
-                               A7FF647A18C52E8500B55307 /* SpillRegistersMode.h */,
                        );
                        path = jit;
                        sourceTree = "<group>";
                                A51007C0187CC3C600B38879 /* JSGlobalObjectInspectorController.cpp in Sources */,
                                A50E4B6318809DD50068A46D /* JSGlobalObjectRuntimeAgent.cpp in Sources */,
                                A503FA29188F105900110F14 /* JSGlobalObjectScriptDebugServer.cpp in Sources */,
+                               0FA7A8EE18CE4FD80052371D /* ScratchRegisterAllocator.cpp in Sources */,
                                A513E5BF185BFACC007E95AD /* JSInjectedScriptHost.cpp in Sources */,
                                A513E5C1185BFACC007E95AD /* JSInjectedScriptHostPrototype.cpp in Sources */,
                                A503FA1B188E0FB000110F14 /* JSJavaScriptCallFrame.cpp in Sources */,
index 30b4f38..e00cc04 100644 (file)
@@ -71,6 +71,9 @@ static CompilationResult compileImpl(
     if (logCompilationChanges(mode))
         dataLog("DFG(Driver) compiling ", *codeBlock, " with ", mode, ", number of instructions = ", codeBlock->instructionCount(), "\n");
     
+    if (codeBlock->alternative()->reoptimizationRetryCounter() >= 2)
+        return CompilationFailed;
+    
     // Make sure that any stubs that the DFG is going to use are initialized. We want to
     // make sure that all JIT code generation does finalization on the main thread.
     vm.getCTIStub(osrExitGenerationThunkGenerator);
diff --git a/Source/JavaScriptCore/jit/ScratchRegisterAllocator.cpp b/Source/JavaScriptCore/jit/ScratchRegisterAllocator.cpp
new file mode 100644 (file)
index 0000000..a6903a9
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * 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 "ScratchRegisterAllocator.h"
+
+#if ENABLE(JIT)
+
+#include "JSCInlines.h"
+#include "VM.h"
+
+namespace JSC {
+
+ScratchRegisterAllocator::ScratchRegisterAllocator(const TempRegisterSet& usedRegisters)
+    : m_usedRegisters(usedRegisters)
+    , m_numberOfReusedRegisters(0)
+{
+}
+
+ScratchRegisterAllocator::~ScratchRegisterAllocator() { }
+
+void ScratchRegisterAllocator::lock(GPRReg reg)
+{
+    unsigned index = GPRInfo::toIndex(reg);
+    if (index == GPRInfo::InvalidIndex)
+        return;
+    m_lockedRegisters.setGPRByIndex(index);
+}
+
+void ScratchRegisterAllocator::lock(FPRReg reg)
+{
+    unsigned index = FPRInfo::toIndex(reg);
+    if (index == FPRInfo::InvalidIndex)
+        return;
+    m_lockedRegisters.setFPRByIndex(index);
+}
+
+template<typename BankInfo>
+typename BankInfo::RegisterType ScratchRegisterAllocator::allocateScratch()
+{
+    // First try to allocate a register that is totally free.
+    for (unsigned i = 0; i < BankInfo::numberOfRegisters; ++i) {
+        typename BankInfo::RegisterType reg = BankInfo::toRegister(i);
+        if (!m_lockedRegisters.get(reg)
+            && !m_usedRegisters.get(reg)
+            && !m_scratchRegisters.get(reg)) {
+            m_scratchRegisters.set(reg);
+            return reg;
+        }
+    }
+        
+    // Since that failed, try to allocate a register that is not yet
+    // locked or used for scratch.
+    for (unsigned i = 0; i < BankInfo::numberOfRegisters; ++i) {
+        typename BankInfo::RegisterType reg = BankInfo::toRegister(i);
+        if (!m_lockedRegisters.get(reg) && !m_scratchRegisters.get(reg)) {
+            m_scratchRegisters.set(reg);
+            m_numberOfReusedRegisters++;
+            return reg;
+        }
+    }
+        
+    // We failed.
+    CRASH();
+    // Make some silly compilers happy.
+    return static_cast<typename BankInfo::RegisterType>(-1);
+}
+
+GPRReg ScratchRegisterAllocator::allocateScratchGPR() { return allocateScratch<GPRInfo>(); }
+FPRReg ScratchRegisterAllocator::allocateScratchFPR() { return allocateScratch<FPRInfo>(); }
+
+void ScratchRegisterAllocator::preserveReusedRegistersByPushing(MacroAssembler& jit)
+{
+    if (!didReuseRegisters())
+        return;
+        
+    for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
+        if (m_scratchRegisters.getFPRByIndex(i) && m_usedRegisters.getFPRByIndex(i))
+            jit.pushToSave(FPRInfo::toRegister(i));
+    }
+    for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
+        if (m_scratchRegisters.getGPRByIndex(i) && m_usedRegisters.getGPRByIndex(i))
+            jit.pushToSave(GPRInfo::toRegister(i));
+    }
+}
+
+void ScratchRegisterAllocator::restoreReusedRegistersByPopping(MacroAssembler& jit)
+{
+    if (!didReuseRegisters())
+        return;
+        
+    for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
+        if (m_scratchRegisters.getGPRByIndex(i) && m_usedRegisters.getGPRByIndex(i))
+            jit.popToRestore(GPRInfo::toRegister(i));
+    }
+    for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
+        if (m_scratchRegisters.getFPRByIndex(i) && m_usedRegisters.getFPRByIndex(i))
+            jit.popToRestore(FPRInfo::toRegister(i));
+    }
+}
+
+unsigned ScratchRegisterAllocator::desiredScratchBufferSize() const
+{
+    return m_usedRegisters.numberOfSetRegisters() * sizeof(JSValue);
+}
+
+void ScratchRegisterAllocator::preserveUsedRegistersToScratchBuffer(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR)
+{
+    unsigned count = 0;
+    for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
+        if (m_usedRegisters.getGPRByIndex(i)) {
+#if USE(JSVALUE64)
+            jit.store64(GPRInfo::toRegister(i), static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++));
+#else
+            jit.store32(GPRInfo::toRegister(i), static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++));
+#endif
+        }
+        if (scratchGPR == InvalidGPRReg && !m_lockedRegisters.getGPRByIndex(i) && !m_scratchRegisters.getGPRByIndex(i))
+            scratchGPR = GPRInfo::toRegister(i);
+    }
+    RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
+    for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
+        if (m_usedRegisters.getFPRByIndex(i)) {
+            jit.move(MacroAssembler::TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++)), scratchGPR);
+            jit.storeDouble(FPRInfo::toRegister(i), scratchGPR);
+        }
+    }
+    RELEASE_ASSERT(count * sizeof(JSValue) == desiredScratchBufferSize());
+    
+    jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratchGPR);
+    jit.storePtr(MacroAssembler::TrustedImmPtr(static_cast<size_t>(count * sizeof(JSValue))), scratchGPR);
+}
+
+void ScratchRegisterAllocator::restoreUsedRegistersFromScratchBuffer(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR)
+{
+    if (scratchGPR == InvalidGPRReg) {
+        // Find a scratch register.
+        for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
+            if (m_lockedRegisters.getGPRByIndex(i) || m_scratchRegisters.getGPRByIndex(i))
+                continue;
+            scratchGPR = GPRInfo::toRegister(i);
+            break;
+        }
+    }
+    RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
+        
+    jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratchGPR);
+    jit.storePtr(MacroAssembler::TrustedImmPtr(0), scratchGPR);
+
+    // Restore double registers first.
+    unsigned count = m_usedRegisters.numberOfSetGPRs();
+    for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
+        if (m_usedRegisters.getFPRByIndex(i)) {
+            jit.move(MacroAssembler::TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++)), scratchGPR);
+            jit.loadDouble(scratchGPR, FPRInfo::toRegister(i));
+        }
+    }
+        
+    count = 0;
+    for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
+        if (m_usedRegisters.getGPRByIndex(i)) {
+#if USE(JSVALUE64)
+            jit.load64(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++), GPRInfo::toRegister(i));
+#else
+            jit.load32(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++), GPRInfo::toRegister(i));
+#endif
+        }
+    }
+}
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
index 5bf995b..57e4815 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 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
 
 namespace JSC {
 
+struct ScratchBuffer;
+
 // This class provides a low-level register allocator for use in stubs.
 
 class ScratchRegisterAllocator {
 public:
-    ScratchRegisterAllocator(const TempRegisterSet& usedRegisters)
-        : m_usedRegisters(usedRegisters)
-        , m_numberOfReusedRegisters(0)
-    {
-    }
+    ScratchRegisterAllocator(const TempRegisterSet& usedRegisters);
+    ~ScratchRegisterAllocator();
 
-    void lock(GPRReg reg)
-    {
-        unsigned index = GPRInfo::toIndex(reg);
-        if (index == GPRInfo::InvalidIndex)
-            return;
-        m_lockedRegisters.setGPRByIndex(index);
-    }
-    void lock(FPRReg reg)
-    {
-        unsigned index = FPRInfo::toIndex(reg);
-        if (index == FPRInfo::InvalidIndex)
-            return;
-        m_lockedRegisters.setFPRByIndex(index);
-    }
+    void lock(GPRReg reg);
+    void lock(FPRReg reg);
     
     template<typename BankInfo>
-    typename BankInfo::RegisterType allocateScratch()
-    {
-        // First try to allocate a register that is totally free.
-        for (unsigned i = 0; i < BankInfo::numberOfRegisters; ++i) {
-            typename BankInfo::RegisterType reg = BankInfo::toRegister(i);
-            if (!m_lockedRegisters.get(reg)
-                && !m_usedRegisters.get(reg)
-                && !m_scratchRegisters.get(reg)) {
-                m_scratchRegisters.set(reg);
-                return reg;
-            }
-        }
-        
-        // Since that failed, try to allocate a register that is not yet
-        // locked or used for scratch.
-        for (unsigned i = 0; i < BankInfo::numberOfRegisters; ++i) {
-            typename BankInfo::RegisterType reg = BankInfo::toRegister(i);
-            if (!m_lockedRegisters.get(reg) && !m_scratchRegisters.get(reg)) {
-                m_scratchRegisters.set(reg);
-                m_numberOfReusedRegisters++;
-                return reg;
-            }
-        }
-        
-        // We failed.
-        CRASH();
-        // Make some silly compilers happy.
-        return static_cast<typename BankInfo::RegisterType>(-1);
-    }
+    typename BankInfo::RegisterType allocateScratch();
     
-    GPRReg allocateScratchGPR() { return allocateScratch<GPRInfo>(); }
-    FPRReg allocateScratchFPR() { return allocateScratch<FPRInfo>(); }
+    GPRReg allocateScratchGPR();
+    FPRReg allocateScratchFPR();
     
     bool didReuseRegisters() const
     {
@@ -102,101 +61,14 @@ public:
         return m_numberOfReusedRegisters;
     }
     
-    void preserveReusedRegistersByPushing(MacroAssembler& jit)
-    {
-        if (!didReuseRegisters())
-            return;
-        
-        for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
-            if (m_scratchRegisters.getFPRByIndex(i) && m_usedRegisters.getFPRByIndex(i))
-                jit.pushToSave(FPRInfo::toRegister(i));
-        }
-        for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
-            if (m_scratchRegisters.getGPRByIndex(i) && m_usedRegisters.getGPRByIndex(i))
-                jit.pushToSave(GPRInfo::toRegister(i));
-        }
-    }
-    
-    void restoreReusedRegistersByPopping(MacroAssembler& jit)
-    {
-        if (!didReuseRegisters())
-            return;
-        
-        for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
-            if (m_scratchRegisters.getGPRByIndex(i) && m_usedRegisters.getGPRByIndex(i))
-                jit.popToRestore(GPRInfo::toRegister(i));
-        }
-        for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
-            if (m_scratchRegisters.getFPRByIndex(i) && m_usedRegisters.getFPRByIndex(i))
-                jit.popToRestore(FPRInfo::toRegister(i));
-        }
-    }
+    void preserveReusedRegistersByPushing(MacroAssembler& jit);
+    void restoreReusedRegistersByPopping(MacroAssembler& jit);
     
-    unsigned desiredScratchBufferSize() const { return m_usedRegisters.numberOfSetRegisters() * sizeof(JSValue); }
+    unsigned desiredScratchBufferSize() const;
     
-    void preserveUsedRegistersToScratchBuffer(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR = InvalidGPRReg)
-    {
-        unsigned count = 0;
-        for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
-            if (m_usedRegisters.getGPRByIndex(i)) {
-#if USE(JSVALUE64)
-                jit.store64(GPRInfo::toRegister(i), static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++));
-#else
-                jit.store32(GPRInfo::toRegister(i), static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++));
-#endif
-            }
-            if (scratchGPR == InvalidGPRReg && !m_lockedRegisters.getGPRByIndex(i) && !m_scratchRegisters.getGPRByIndex(i))
-                scratchGPR = GPRInfo::toRegister(i);
-        }
-        RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
-        for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
-            if (m_usedRegisters.getFPRByIndex(i)) {
-                jit.move(MacroAssembler::TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++)), scratchGPR);
-                jit.storeDouble(FPRInfo::toRegister(i), scratchGPR);
-            }
-        }
-        RELEASE_ASSERT(count * sizeof(JSValue) == desiredScratchBufferSize());
-        
-        jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratchGPR);
-        jit.storePtr(MacroAssembler::TrustedImmPtr(static_cast<size_t>(count * sizeof(JSValue))), scratchGPR);
-    }
+    void preserveUsedRegistersToScratchBuffer(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR = InvalidGPRReg);
     
-    void restoreUsedRegistersFromScratchBuffer(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR = InvalidGPRReg)
-    {
-        if (scratchGPR == InvalidGPRReg) {
-            // Find a scratch register.
-            for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
-                if (m_lockedRegisters.getGPRByIndex(i) || m_scratchRegisters.getGPRByIndex(i))
-                    continue;
-                scratchGPR = GPRInfo::toRegister(i);
-                break;
-            }
-        }
-        RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
-        
-        jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratchGPR);
-        jit.storePtr(MacroAssembler::TrustedImmPtr(0), scratchGPR);
-
-        // Restore double registers first.
-        unsigned count = m_usedRegisters.numberOfSetGPRs();
-        for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
-            if (m_usedRegisters.getFPRByIndex(i)) {
-                jit.move(MacroAssembler::TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++)), scratchGPR);
-                jit.loadDouble(scratchGPR, FPRInfo::toRegister(i));
-            }
-        }
-        
-        count = 0;
-        for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
-            if (m_usedRegisters.getGPRByIndex(i)) {
-#if USE(JSVALUE64)
-                jit.load64(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++), GPRInfo::toRegister(i));
-#else
-                jit.load32(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++), GPRInfo::toRegister(i));
-#endif
-            }
-        }
-    }
+    void restoreUsedRegistersFromScratchBuffer(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR = InvalidGPRReg);
     
 private:
     TempRegisterSet m_usedRegisters;
@@ -210,4 +82,3 @@ private:
 #endif // ENABLE(JIT)
 
 #endif // ScratchRegisterAllocator_h
-