]> git.saurik.com Git - apple/javascriptcore.git/blame - jit/ScratchRegisterAllocator.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / jit / ScratchRegisterAllocator.cpp
CommitLineData
81345200
A
1/*
2 * Copyright (C) 2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
24 */
25
26#include "config.h"
27#include "ScratchRegisterAllocator.h"
28
29#if ENABLE(JIT)
30
31#include "JSCInlines.h"
32#include "VM.h"
33
34namespace JSC {
35
36ScratchRegisterAllocator::ScratchRegisterAllocator(const RegisterSet& usedRegisters)
37 : m_usedRegisters(usedRegisters)
38 , m_numberOfReusedRegisters(0)
39{
40}
41
42ScratchRegisterAllocator::~ScratchRegisterAllocator() { }
43
44void ScratchRegisterAllocator::lock(GPRReg reg)
45{
46 unsigned index = GPRInfo::toIndex(reg);
47 if (index == GPRInfo::InvalidIndex)
48 return;
49 m_lockedRegisters.setGPRByIndex(index);
50}
51
52void ScratchRegisterAllocator::lock(FPRReg reg)
53{
54 unsigned index = FPRInfo::toIndex(reg);
55 if (index == FPRInfo::InvalidIndex)
56 return;
57 m_lockedRegisters.setFPRByIndex(index);
58}
59
60template<typename BankInfo>
61typename BankInfo::RegisterType ScratchRegisterAllocator::allocateScratch()
62{
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);
70 return reg;
71 }
72 }
73
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++;
81 return reg;
82 }
83 }
84
85 // We failed.
86 CRASH();
87 // Make some silly compilers happy.
88 return static_cast<typename BankInfo::RegisterType>(-1);
89}
90
91GPRReg ScratchRegisterAllocator::allocateScratchGPR() { return allocateScratch<GPRInfo>(); }
92FPRReg ScratchRegisterAllocator::allocateScratchFPR() { return allocateScratch<FPRInfo>(); }
93
94void ScratchRegisterAllocator::preserveReusedRegistersByPushing(MacroAssembler& jit)
95{
96 if (!didReuseRegisters())
97 return;
98
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))
102 jit.pushToSave(reg);
103 }
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))
107 jit.pushToSave(reg);
108 }
109}
110
111void ScratchRegisterAllocator::restoreReusedRegistersByPopping(MacroAssembler& jit)
112{
113 if (!didReuseRegisters())
114 return;
115
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);
120 }
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);
125 }
126}
127
128RegisterSet ScratchRegisterAllocator::usedRegistersForCall() const
129{
130 RegisterSet result = m_usedRegisters;
131 result.exclude(RegisterSet::calleeSaveRegisters());
132 result.exclude(RegisterSet::stackRegisters());
133 result.exclude(RegisterSet::reservedHardwareRegisters());
134 return result;
135}
136
137unsigned ScratchRegisterAllocator::desiredScratchBufferSizeForCall() const
138{
139 return usedRegistersForCall().numberOfSetRegisters() * sizeof(JSValue);
140}
141
142void ScratchRegisterAllocator::preserveUsedRegistersToScratchBufferForCall(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR)
143{
144 RegisterSet usedRegisters = usedRegistersForCall();
145 if (!usedRegisters.numberOfSetRegisters())
146 return;
147
148 unsigned count = 0;
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))
155 scratchGPR = reg;
156 }
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);
162 }
163 }
164 RELEASE_ASSERT(count * sizeof(JSValue) == desiredScratchBufferSizeForCall());
165
166 jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratchGPR);
167 jit.storePtr(MacroAssembler::TrustedImmPtr(static_cast<size_t>(count * sizeof(JSValue))), scratchGPR);
168}
169
170void ScratchRegisterAllocator::restoreUsedRegistersFromScratchBufferForCall(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR)
171{
172 RegisterSet usedRegisters = usedRegistersForCall();
173 if (!usedRegisters.numberOfSetRegisters())
174 return;
175
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))
180 continue;
181 scratchGPR = GPRInfo::toRegister(i);
182 break;
183 }
184 }
185 RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
186
187 jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratchGPR);
188 jit.storePtr(MacroAssembler::TrustedImmPtr(0), scratchGPR);
189
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);
196 }
197 }
198
199 count = 0;
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);
203 }
204}
205
206} // namespace JSC
207
208#endif // ENABLE(JIT)