]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGScratchRegisterAllocator.h
JavaScriptCore-1218.33.tar.gz
[apple/javascriptcore.git] / dfg / DFGScratchRegisterAllocator.h
1 /*
2 * Copyright (C) 2012 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 #ifndef DFGScratchRegisterAllocator_h
27 #define DFGScratchRegisterAllocator_h
28
29 #include <wtf/Platform.h>
30
31 #if ENABLE(DFG_JIT)
32
33 #include "DFGRegisterSet.h"
34 #include "MacroAssembler.h"
35
36 namespace JSC { namespace DFG {
37
38 // This class provides a low-level register allocator for use in stubs.
39
40 class ScratchRegisterAllocator {
41 public:
42 ScratchRegisterAllocator(const RegisterSet& usedRegisters)
43 : m_usedRegisters(usedRegisters)
44 , m_didReuseRegisters(false)
45 {
46 }
47
48 template<typename T>
49 void lock(T reg) { m_lockedRegisters.set(reg); }
50
51 template<typename BankInfo>
52 typename BankInfo::RegisterType allocateScratch()
53 {
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);
61 return reg;
62 }
63 }
64
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;
72 return reg;
73 }
74 }
75
76 // We failed.
77 CRASH();
78 // Make some silly compilers happy.
79 return static_cast<typename BankInfo::RegisterType>(-1);
80 }
81
82 GPRReg allocateScratchGPR() { return allocateScratch<GPRInfo>(); }
83 FPRReg allocateScratchFPR() { return allocateScratch<FPRInfo>(); }
84
85 bool didReuseRegisters() const
86 {
87 return m_didReuseRegisters;
88 }
89
90 void preserveReusedRegistersByPushing(MacroAssembler& jit)
91 {
92 if (!m_didReuseRegisters)
93 return;
94
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));
98 }
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));
102 }
103 }
104
105 void restoreReusedRegistersByPopping(MacroAssembler& jit)
106 {
107 if (!m_didReuseRegisters)
108 return;
109
110 for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
111 if (m_scratchRegisters.getGPRByIndex(i) && m_usedRegisters.getGPRByIndex(i))
112 jit.popToRestore(GPRInfo::toRegister(i));
113 }
114 for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
115 if (m_scratchRegisters.getFPRByIndex(i) && m_usedRegisters.getFPRByIndex(i))
116 jit.popToRestore(FPRInfo::toRegister(i));
117 }
118 }
119
120 unsigned desiredScratchBufferSize() const { return m_usedRegisters.numberOfSetRegisters() * sizeof(JSValue); }
121
122 void preserveUsedRegistersToScratchBuffer(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR = InvalidGPRReg)
123 {
124 unsigned count = 0;
125 for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
126 if (m_usedRegisters.getGPRByIndex(i)) {
127 #if USE(JSVALUE64)
128 jit.store64(GPRInfo::toRegister(i), static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++));
129 #else
130 jit.store32(GPRInfo::toRegister(i), static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++));
131 #endif
132 }
133 if (scratchGPR == InvalidGPRReg && !m_lockedRegisters.getGPRByIndex(i) && !m_scratchRegisters.getGPRByIndex(i))
134 scratchGPR = GPRInfo::toRegister(i);
135 }
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);
141 }
142 }
143 RELEASE_ASSERT(count * sizeof(JSValue) == desiredScratchBufferSize());
144
145 jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratchGPR);
146 jit.storePtr(MacroAssembler::TrustedImmPtr(static_cast<size_t>(count * sizeof(JSValue))), scratchGPR);
147 }
148
149 void restoreUsedRegistersFromScratchBuffer(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR = InvalidGPRReg)
150 {
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))
155 continue;
156 scratchGPR = GPRInfo::toRegister(i);
157 break;
158 }
159 }
160 RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
161
162 jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratchGPR);
163 jit.storePtr(MacroAssembler::TrustedImmPtr(0), scratchGPR);
164
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));
171 }
172 }
173
174 count = 0;
175 for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
176 if (m_usedRegisters.getGPRByIndex(i)) {
177 #if USE(JSVALUE64)
178 jit.load64(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++), GPRInfo::toRegister(i));
179 #else
180 jit.load32(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++), GPRInfo::toRegister(i));
181 #endif
182 }
183 }
184 }
185
186 private:
187 RegisterSet m_usedRegisters;
188 RegisterSet m_lockedRegisters;
189 RegisterSet m_scratchRegisters;
190 bool m_didReuseRegisters;
191 };
192
193 } } // namespace JSC::DFG
194
195 #endif // ENABLE(DFG_JIT)
196
197 #endif // DFGScratchRegisterAllocator_h
198