2 * Copyright (C) 2014 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.
27 #include "ScratchRegisterAllocator.h"
31 #include "JSCInlines.h"
36 ScratchRegisterAllocator::ScratchRegisterAllocator(const RegisterSet
& usedRegisters
)
37 : m_usedRegisters(usedRegisters
)
38 , m_numberOfReusedRegisters(0)
42 ScratchRegisterAllocator::~ScratchRegisterAllocator() { }
44 void ScratchRegisterAllocator::lock(GPRReg reg
)
46 unsigned index
= GPRInfo::toIndex(reg
);
47 if (index
== GPRInfo::InvalidIndex
)
49 m_lockedRegisters
.setGPRByIndex(index
);
52 void ScratchRegisterAllocator::lock(FPRReg reg
)
54 unsigned index
= FPRInfo::toIndex(reg
);
55 if (index
== FPRInfo::InvalidIndex
)
57 m_lockedRegisters
.setFPRByIndex(index
);
60 template<typename BankInfo
>
61 typename
BankInfo::RegisterType
ScratchRegisterAllocator::allocateScratch()
63 // First try to allocate a register that is totally free.
64 for (unsigned i
= 0; i
< BankInfo::numberOfRegisters
; ++i
) {
65 typename
BankInfo::RegisterType reg
= BankInfo::toRegister(i
);
66 if (!m_lockedRegisters
.get(reg
)
67 && !m_usedRegisters
.get(reg
)
68 && !m_scratchRegisters
.get(reg
)) {
69 m_scratchRegisters
.set(reg
);
74 // Since that failed, try to allocate a register that is not yet
75 // locked or used for scratch.
76 for (unsigned i
= 0; i
< BankInfo::numberOfRegisters
; ++i
) {
77 typename
BankInfo::RegisterType reg
= BankInfo::toRegister(i
);
78 if (!m_lockedRegisters
.get(reg
) && !m_scratchRegisters
.get(reg
)) {
79 m_scratchRegisters
.set(reg
);
80 m_numberOfReusedRegisters
++;
87 // Make some silly compilers happy.
88 return static_cast<typename
BankInfo::RegisterType
>(-1);
91 GPRReg
ScratchRegisterAllocator::allocateScratchGPR() { return allocateScratch
<GPRInfo
>(); }
92 FPRReg
ScratchRegisterAllocator::allocateScratchFPR() { return allocateScratch
<FPRInfo
>(); }
94 void ScratchRegisterAllocator::preserveReusedRegistersByPushing(MacroAssembler
& jit
)
96 if (!didReuseRegisters())
99 for (unsigned i
= 0; i
< FPRInfo::numberOfRegisters
; ++i
) {
100 FPRReg reg
= FPRInfo::toRegister(i
);
101 if (m_scratchRegisters
.getFPRByIndex(i
) && m_usedRegisters
.get(reg
))
104 for (unsigned i
= 0; i
< GPRInfo::numberOfRegisters
; ++i
) {
105 GPRReg reg
= GPRInfo::toRegister(i
);
106 if (m_scratchRegisters
.getGPRByIndex(i
) && m_usedRegisters
.get(reg
))
111 void ScratchRegisterAllocator::restoreReusedRegistersByPopping(MacroAssembler
& jit
)
113 if (!didReuseRegisters())
116 for (unsigned i
= GPRInfo::numberOfRegisters
; i
--;) {
117 GPRReg reg
= GPRInfo::toRegister(i
);
118 if (m_scratchRegisters
.getGPRByIndex(i
) && m_usedRegisters
.get(reg
))
119 jit
.popToRestore(reg
);
121 for (unsigned i
= FPRInfo::numberOfRegisters
; i
--;) {
122 FPRReg reg
= FPRInfo::toRegister(i
);
123 if (m_scratchRegisters
.getFPRByIndex(i
) && m_usedRegisters
.get(reg
))
124 jit
.popToRestore(reg
);
128 RegisterSet
ScratchRegisterAllocator::usedRegistersForCall() const
130 RegisterSet result
= m_usedRegisters
;
131 result
.exclude(RegisterSet::calleeSaveRegisters());
132 result
.exclude(RegisterSet::stackRegisters());
133 result
.exclude(RegisterSet::reservedHardwareRegisters());
137 unsigned ScratchRegisterAllocator::desiredScratchBufferSizeForCall() const
139 return usedRegistersForCall().numberOfSetRegisters() * sizeof(JSValue
);
142 void ScratchRegisterAllocator::preserveUsedRegistersToScratchBufferForCall(MacroAssembler
& jit
, ScratchBuffer
* scratchBuffer
, GPRReg scratchGPR
)
144 RegisterSet usedRegisters
= usedRegistersForCall();
145 if (!usedRegisters
.numberOfSetRegisters())
149 for (GPRReg reg
= MacroAssembler::firstRegister(); reg
<= MacroAssembler::lastRegister(); reg
= MacroAssembler::nextRegister(reg
)) {
150 if (usedRegisters
.get(reg
))
151 jit
.storePtr(reg
, static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer()) + (count
++));
152 if (GPRInfo::toIndex(reg
) != GPRInfo::InvalidIndex
153 && scratchGPR
== InvalidGPRReg
154 && !m_lockedRegisters
.get(reg
) && !m_scratchRegisters
.get(reg
))
157 RELEASE_ASSERT(scratchGPR
!= InvalidGPRReg
);
158 for (FPRReg reg
= MacroAssembler::firstFPRegister(); reg
<= MacroAssembler::lastFPRegister(); reg
= MacroAssembler::nextFPRegister(reg
)) {
159 if (usedRegisters
.get(reg
)) {
160 jit
.move(MacroAssembler::TrustedImmPtr(static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer()) + (count
++)), scratchGPR
);
161 jit
.storeDouble(reg
, scratchGPR
);
164 RELEASE_ASSERT(count
* sizeof(JSValue
) == desiredScratchBufferSizeForCall());
166 jit
.move(MacroAssembler::TrustedImmPtr(scratchBuffer
->activeLengthPtr()), scratchGPR
);
167 jit
.storePtr(MacroAssembler::TrustedImmPtr(static_cast<size_t>(count
* sizeof(JSValue
))), scratchGPR
);
170 void ScratchRegisterAllocator::restoreUsedRegistersFromScratchBufferForCall(MacroAssembler
& jit
, ScratchBuffer
* scratchBuffer
, GPRReg scratchGPR
)
172 RegisterSet usedRegisters
= usedRegistersForCall();
173 if (!usedRegisters
.numberOfSetRegisters())
176 if (scratchGPR
== InvalidGPRReg
) {
177 // Find a scratch register.
178 for (unsigned i
= GPRInfo::numberOfRegisters
; i
--;) {
179 if (m_lockedRegisters
.getGPRByIndex(i
) || m_scratchRegisters
.getGPRByIndex(i
))
181 scratchGPR
= GPRInfo::toRegister(i
);
185 RELEASE_ASSERT(scratchGPR
!= InvalidGPRReg
);
187 jit
.move(MacroAssembler::TrustedImmPtr(scratchBuffer
->activeLengthPtr()), scratchGPR
);
188 jit
.storePtr(MacroAssembler::TrustedImmPtr(0), scratchGPR
);
190 // Restore double registers first.
191 unsigned count
= usedRegisters
.numberOfSetGPRs();
192 for (FPRReg reg
= MacroAssembler::firstFPRegister(); reg
<= MacroAssembler::lastFPRegister(); reg
= MacroAssembler::nextFPRegister(reg
)) {
193 if (usedRegisters
.get(reg
)) {
194 jit
.move(MacroAssembler::TrustedImmPtr(static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer()) + (count
++)), scratchGPR
);
195 jit
.loadDouble(scratchGPR
, reg
);
200 for (GPRReg reg
= MacroAssembler::firstRegister(); reg
<= MacroAssembler::lastRegister(); reg
= MacroAssembler::nextRegister(reg
)) {
201 if (usedRegisters
.get(reg
))
202 jit
.loadPtr(static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer()) + (count
++), reg
);
208 #endif // ENABLE(JIT)