]> git.saurik.com Git - apple/javascriptcore.git/blob - interpreter/RegisterFile.h
f59c13a1b5327e7e4cf25f79c9c8b1cc1f6fed69
[apple/javascriptcore.git] / interpreter / RegisterFile.h
1 /*
2 * Copyright (C) 2008, 2009 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 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #ifndef RegisterFile_h
30 #define RegisterFile_h
31
32 #include "Heap.h"
33 #include "ExecutableAllocator.h"
34 #include "Register.h"
35 #include "Weak.h"
36 #include <stdio.h>
37 #include <wtf/Noncopyable.h>
38 #include <wtf/PageReservation.h>
39 #include <wtf/VMTags.h>
40
41 namespace JSC {
42
43 /*
44 A register file is a stack of register frames. We represent a register
45 frame by its offset from "base", the logical first entry in the register
46 file. The bottom-most register frame's offset from base is 0.
47
48 In a program where function "a" calls function "b" (global code -> a -> b),
49 the register file might look like this:
50
51 | global frame | call frame | call frame | spare capacity |
52 -----------------------------------------------------------------------------------------------------
53 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | | | | | | <-- index in buffer
54 -----------------------------------------------------------------------------------------------------
55 | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | | | | | | <-- index relative to base
56 -----------------------------------------------------------------------------------------------------
57 | <-globals | temps-> | <-vars | temps-> | <-vars |
58 ^ ^ ^ ^
59 | | | |
60 buffer base (frame 0) frame 1 frame 2
61
62 Since all variables, including globals, are accessed by negative offsets
63 from their register frame pointers, to keep old global offsets correct, new
64 globals must appear at the beginning of the register file, shifting base
65 to the right.
66
67 If we added one global variable to the register file depicted above, it
68 would look like this:
69
70 | global frame |< >
71 -------------------------------> <
72 | 0 | 1 | 2 | 3 | 4 | 5 |< >snip< > <-- index in buffer
73 -------------------------------> <
74 | -4 | -3 | -2 | -1 | 0 | 1 |< > <-- index relative to base
75 -------------------------------> <
76 | <-globals | temps-> |
77 ^ ^
78 | |
79 buffer base (frame 0)
80
81 As you can see, global offsets relative to base have stayed constant,
82 but base itself has moved. To keep up with possible changes to base,
83 clients keep an indirect pointer, so their calculations update
84 automatically when base changes.
85
86 For client simplicity, the RegisterFile measures size and capacity from
87 "base", not "buffer".
88 */
89
90 class JSGlobalObject;
91
92 class RegisterFile {
93 WTF_MAKE_NONCOPYABLE(RegisterFile);
94 public:
95 enum CallFrameHeaderEntry {
96 CallFrameHeaderSize = 6,
97
98 ArgumentCount = -6,
99 CallerFrame = -5,
100 Callee = -4,
101 ScopeChain = -3,
102 ReturnPC = -2, // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
103 CodeBlock = -1,
104 };
105
106 enum { ProgramCodeThisRegister = -CallFrameHeaderSize - 1 };
107
108 static const size_t defaultCapacity = 512 * 1024;
109 static const size_t defaultMaxGlobals = 8 * 1024;
110 static const size_t commitSize = 16 * 1024;
111 // Allow 8k of excess registers before we start trying to reap the registerfile
112 static const ptrdiff_t maxExcessCapacity = 8 * 1024;
113
114 RegisterFile(JSGlobalData&, size_t capacity = defaultCapacity, size_t maxGlobals = defaultMaxGlobals);
115 ~RegisterFile();
116
117 void gatherConservativeRoots(ConservativeRoots&);
118
119 Register* start() const { return m_start; }
120 Register* end() const { return m_end; }
121 size_t size() const { return m_end - m_start; }
122
123 void setGlobalObject(JSGlobalObject*);
124 JSGlobalObject* globalObject();
125
126 bool grow(Register* newEnd);
127 void shrink(Register* newEnd);
128
129 void setNumGlobals(size_t numGlobals) { m_numGlobals = numGlobals; }
130 int numGlobals() const { return m_numGlobals; }
131 size_t maxGlobals() const { return m_maxGlobals; }
132
133 Register* lastGlobal() const { return m_start - m_numGlobals; }
134
135 static size_t committedByteCount();
136 static void initializeThreading();
137
138 Register* const * addressOfEnd() const
139 {
140 return &m_end;
141 }
142
143 private:
144 void releaseExcessCapacity();
145 void addToCommittedByteCount(long);
146 size_t m_numGlobals;
147 const size_t m_maxGlobals;
148 Register* m_start;
149 Register* m_end;
150 Register* m_max;
151 Register* m_maxUsed;
152 Register* m_commitEnd;
153 PageReservation m_reservation;
154
155 Weak<JSGlobalObject> m_globalObject; // The global object whose vars are currently stored in the register file.
156 class GlobalObjectOwner : public WeakHandleOwner {
157 virtual void finalize(Handle<Unknown>, void* context)
158 {
159 static_cast<RegisterFile*>(context)->setNumGlobals(0);
160 }
161 } m_globalObjectOwner;
162 };
163
164 inline RegisterFile::RegisterFile(JSGlobalData& globalData, size_t capacity, size_t maxGlobals)
165 : m_numGlobals(0)
166 , m_maxGlobals(maxGlobals)
167 , m_start(0)
168 , m_end(0)
169 , m_max(0)
170 , m_globalObject(globalData, 0, &m_globalObjectOwner, this)
171 {
172 ASSERT(maxGlobals && isPageAligned(maxGlobals));
173 ASSERT(capacity && isPageAligned(capacity));
174 size_t bufferLength = (capacity + maxGlobals) * sizeof(Register);
175 m_reservation = PageReservation::reserve(roundUpAllocationSize(bufferLength, commitSize), OSAllocator::JSVMStackPages);
176 void* base = m_reservation.base();
177 size_t committedSize = roundUpAllocationSize(maxGlobals * sizeof(Register), commitSize);
178 m_reservation.commit(base, committedSize);
179 addToCommittedByteCount(static_cast<long>(committedSize));
180 m_commitEnd = reinterpret_cast_ptr<Register*>(reinterpret_cast<char*>(base) + committedSize);
181 m_start = static_cast<Register*>(base) + maxGlobals;
182 m_end = m_start;
183 m_maxUsed = m_end;
184 m_max = m_start + capacity;
185 }
186
187 inline void RegisterFile::shrink(Register* newEnd)
188 {
189 if (newEnd >= m_end)
190 return;
191 m_end = newEnd;
192 if (m_end == m_start && (m_maxUsed - m_start) > maxExcessCapacity)
193 releaseExcessCapacity();
194 }
195
196 inline bool RegisterFile::grow(Register* newEnd)
197 {
198 if (newEnd < m_end)
199 return true;
200
201 if (newEnd > m_max)
202 return false;
203
204 if (newEnd > m_commitEnd) {
205 size_t size = roundUpAllocationSize(reinterpret_cast<char*>(newEnd) - reinterpret_cast<char*>(m_commitEnd), commitSize);
206 m_reservation.commit(m_commitEnd, size);
207 addToCommittedByteCount(static_cast<long>(size));
208 m_commitEnd = reinterpret_cast_ptr<Register*>(reinterpret_cast<char*>(m_commitEnd) + size);
209 }
210
211 if (newEnd > m_maxUsed)
212 m_maxUsed = newEnd;
213
214 m_end = newEnd;
215 return true;
216 }
217
218 } // namespace JSC
219
220 #endif // RegisterFile_h