2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #ifndef DFGScratchRegisterAllocator_h
27 #define DFGScratchRegisterAllocator_h
29 #include <wtf/Platform.h>
33 #include "DFGRegisterSet.h"
34 #include "MacroAssembler.h"
36 namespace JSC
{ namespace DFG
{
38 // This class provides a low-level register allocator for use in stubs.
40 class ScratchRegisterAllocator
{
42 ScratchRegisterAllocator(const RegisterSet
& usedRegisters
)
43 : m_usedRegisters(usedRegisters
)
44 , m_didReuseRegisters(false)
49 void lock(T reg
) { m_lockedRegisters
.set(reg
); }
51 template<typename BankInfo
>
52 typename
BankInfo::RegisterType
allocateScratch()
54 // First try to allocate a register that is totally free.
55 for (unsigned i
= 0; i
< BankInfo::numberOfRegisters
; ++i
) {
56 typename
BankInfo::RegisterType reg
= BankInfo::toRegister(i
);
57 if (!m_lockedRegisters
.get(reg
)
58 && !m_usedRegisters
.get(reg
)
59 && !m_scratchRegisters
.get(reg
)) {
60 m_scratchRegisters
.set(reg
);
65 // Since that failed, try to allocate a register that is not yet
66 // locked or used for scratch.
67 for (unsigned i
= 0; i
< BankInfo::numberOfRegisters
; ++i
) {
68 typename
BankInfo::RegisterType reg
= BankInfo::toRegister(i
);
69 if (!m_lockedRegisters
.get(reg
) && !m_scratchRegisters
.get(reg
)) {
70 m_scratchRegisters
.set(reg
);
71 m_didReuseRegisters
= true;
78 // Make some silly compilers happy.
79 return static_cast<typename
BankInfo::RegisterType
>(-1);
82 GPRReg
allocateScratchGPR() { return allocateScratch
<GPRInfo
>(); }
83 FPRReg
allocateScratchFPR() { return allocateScratch
<FPRInfo
>(); }
85 bool didReuseRegisters() const
87 return m_didReuseRegisters
;
90 void preserveReusedRegistersByPushing(MacroAssembler
& jit
)
92 if (!m_didReuseRegisters
)
95 for (unsigned i
= 0; i
< FPRInfo::numberOfRegisters
; ++i
) {
96 if (m_scratchRegisters
.getFPRByIndex(i
) && m_usedRegisters
.getFPRByIndex(i
))
97 jit
.pushToSave(FPRInfo::toRegister(i
));
99 for (unsigned i
= 0; i
< GPRInfo::numberOfRegisters
; ++i
) {
100 if (m_scratchRegisters
.getGPRByIndex(i
) && m_usedRegisters
.getGPRByIndex(i
))
101 jit
.pushToSave(GPRInfo::toRegister(i
));
105 void restoreReusedRegistersByPopping(MacroAssembler
& jit
)
107 if (!m_didReuseRegisters
)
110 for (unsigned i
= GPRInfo::numberOfRegisters
; i
--;) {
111 if (m_scratchRegisters
.getGPRByIndex(i
) && m_usedRegisters
.getGPRByIndex(i
))
112 jit
.popToRestore(GPRInfo::toRegister(i
));
114 for (unsigned i
= FPRInfo::numberOfRegisters
; i
--;) {
115 if (m_scratchRegisters
.getFPRByIndex(i
) && m_usedRegisters
.getFPRByIndex(i
))
116 jit
.popToRestore(FPRInfo::toRegister(i
));
120 unsigned desiredScratchBufferSize() const { return m_usedRegisters
.numberOfSetRegisters() * sizeof(JSValue
); }
122 void preserveUsedRegistersToScratchBuffer(MacroAssembler
& jit
, ScratchBuffer
* scratchBuffer
, GPRReg scratchGPR
= InvalidGPRReg
)
125 for (unsigned i
= GPRInfo::numberOfRegisters
; i
--;) {
126 if (m_usedRegisters
.getGPRByIndex(i
)) {
128 jit
.store64(GPRInfo::toRegister(i
), static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer()) + (count
++));
130 jit
.store32(GPRInfo::toRegister(i
), static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer()) + (count
++));
133 if (scratchGPR
== InvalidGPRReg
&& !m_lockedRegisters
.getGPRByIndex(i
) && !m_scratchRegisters
.getGPRByIndex(i
))
134 scratchGPR
= GPRInfo::toRegister(i
);
136 RELEASE_ASSERT(scratchGPR
!= InvalidGPRReg
);
137 for (unsigned i
= FPRInfo::numberOfRegisters
; i
--;) {
138 if (m_usedRegisters
.getFPRByIndex(i
)) {
139 jit
.move(MacroAssembler::TrustedImmPtr(static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer()) + (count
++)), scratchGPR
);
140 jit
.storeDouble(FPRInfo::toRegister(i
), scratchGPR
);
143 RELEASE_ASSERT(count
* sizeof(JSValue
) == desiredScratchBufferSize());
145 jit
.move(MacroAssembler::TrustedImmPtr(scratchBuffer
->activeLengthPtr()), scratchGPR
);
146 jit
.storePtr(MacroAssembler::TrustedImmPtr(static_cast<size_t>(count
* sizeof(JSValue
))), scratchGPR
);
149 void restoreUsedRegistersFromScratchBuffer(MacroAssembler
& jit
, ScratchBuffer
* scratchBuffer
, GPRReg scratchGPR
= InvalidGPRReg
)
151 if (scratchGPR
== InvalidGPRReg
) {
152 // Find a scratch register.
153 for (unsigned i
= GPRInfo::numberOfRegisters
; i
--;) {
154 if (m_lockedRegisters
.getGPRByIndex(i
) || m_scratchRegisters
.getGPRByIndex(i
))
156 scratchGPR
= GPRInfo::toRegister(i
);
160 RELEASE_ASSERT(scratchGPR
!= InvalidGPRReg
);
162 jit
.move(MacroAssembler::TrustedImmPtr(scratchBuffer
->activeLengthPtr()), scratchGPR
);
163 jit
.storePtr(MacroAssembler::TrustedImmPtr(0), scratchGPR
);
165 // Restore double registers first.
166 unsigned count
= m_usedRegisters
.numberOfSetGPRs();
167 for (unsigned i
= FPRInfo::numberOfRegisters
; i
--;) {
168 if (m_usedRegisters
.getFPRByIndex(i
)) {
169 jit
.move(MacroAssembler::TrustedImmPtr(static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer()) + (count
++)), scratchGPR
);
170 jit
.loadDouble(scratchGPR
, FPRInfo::toRegister(i
));
175 for (unsigned i
= GPRInfo::numberOfRegisters
; i
--;) {
176 if (m_usedRegisters
.getGPRByIndex(i
)) {
178 jit
.load64(static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer()) + (count
++), GPRInfo::toRegister(i
));
180 jit
.load32(static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer()) + (count
++), GPRInfo::toRegister(i
));
187 RegisterSet m_usedRegisters
;
188 RegisterSet m_lockedRegisters
;
189 RegisterSet m_scratchRegisters
;
190 bool m_didReuseRegisters
;
193 } } // namespace JSC::DFG
195 #endif // ENABLE(DFG_JIT)
197 #endif // DFGScratchRegisterAllocator_h