source: webkit/trunk/JavaScriptCore/interpreter/RegisterFile.h@ 42676

Last change on this file since 42676 was 42676, checked in by [email protected], 16 years ago

2009-04-20 Sam Weinig <[email protected]>

Reviewed by Kevin McCullough.

Always tag mmaped memory on darwin and clean up #defines
now that they are a little bigger.

  • interpreter/RegisterFile.h: (JSC::RegisterFile::RegisterFile):
  • jit/ExecutableAllocatorFixedVMPool.cpp: (JSC::FixedVMPoolAllocator::FixedVMPoolAllocator):
  • jit/ExecutableAllocatorPosix.cpp: (JSC::ExecutablePool::systemAlloc):
  • runtime/Collector.cpp: (JSC::allocateBlock):
File size: 9.7 KB
Line 
1/*
2 * Copyright (C) 2008 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 "ExecutableAllocator.h"
33#include "Register.h"
34#include "Collector.h"
35#include <wtf/Noncopyable.h>
36
37#if HAVE(MMAP)
38#include <errno.h>
39#include <stdio.h>
40#include <sys/mman.h>
41#endif
42
43#if PLATFORM(DARWIN)
44#include <mach/vm_statistics.h>
45#endif
46
47#if PLATFORM(DARWIN)
48// On Mac OS X, the VM subsystem allows tagging memory requested from mmap and vm_map
49// in order to aid tools that inspect system memory use.
50#if defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
51#define TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
52#else
53#define TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(65)
54#endif
55#else
56#define TAG_FOR_REGISTERFILE_MEMORY -1
57#endif
58
59namespace JSC {
60
61/*
62 A register file is a stack of register frames. We represent a register
63 frame by its offset from "base", the logical first entry in the register
64 file. The bottom-most register frame's offset from base is 0.
65
66 In a program where function "a" calls function "b" (global code -> a -> b),
67 the register file might look like this:
68
69 | global frame | call frame | call frame | spare capacity |
70 -----------------------------------------------------------------------------------------------------
71 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | | | | | | <-- index in buffer
72 -----------------------------------------------------------------------------------------------------
73 | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | | | | | | <-- index relative to base
74 -----------------------------------------------------------------------------------------------------
75 | <-globals | temps-> | <-vars | temps-> | <-vars |
76 ^ ^ ^ ^
77 | | | |
78 buffer base (frame 0) frame 1 frame 2
79
80 Since all variables, including globals, are accessed by negative offsets
81 from their register frame pointers, to keep old global offsets correct, new
82 globals must appear at the beginning of the register file, shifting base
83 to the right.
84
85 If we added one global variable to the register file depicted above, it
86 would look like this:
87
88 | global frame |< >
89 -------------------------------> <
90 | 0 | 1 | 2 | 3 | 4 | 5 |< >snip< > <-- index in buffer
91 -------------------------------> <
92 | -4 | -3 | -2 | -1 | 0 | 1 |< > <-- index relative to base
93 -------------------------------> <
94 | <-globals | temps-> |
95 ^ ^
96 | |
97 buffer base (frame 0)
98
99 As you can see, global offsets relative to base have stayed constant,
100 but base itself has moved. To keep up with possible changes to base,
101 clients keep an indirect pointer, so their calculations update
102 automatically when base changes.
103
104 For client simplicity, the RegisterFile measures size and capacity from
105 "base", not "buffer".
106*/
107
108 class JSGlobalObject;
109
110 class RegisterFile : Noncopyable {
111 friend class JIT;
112 public:
113 enum CallFrameHeaderEntry {
114 CallFrameHeaderSize = 8,
115
116 CodeBlock = -8,
117 ScopeChain = -7,
118 CallerFrame = -6,
119 ReturnPC = -5, // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
120 ReturnValueRegister = -4,
121 ArgumentCount = -3,
122 Callee = -2,
123 OptionalCalleeArguments = -1,
124 };
125
126 enum { ProgramCodeThisRegister = -CallFrameHeaderSize - 1 };
127 enum { ArgumentsRegister = 0 };
128
129 static const size_t defaultCapacity = 524288;
130 static const size_t defaultMaxGlobals = 8192;
131 static const size_t commitSize = 1 << 14;
132
133 RegisterFile(size_t capacity = defaultCapacity, size_t maxGlobals = defaultMaxGlobals);
134 ~RegisterFile();
135
136 Register* start() const { return m_start; }
137 Register* end() const { return m_end; }
138 size_t size() const { return m_end - m_start; }
139
140 void setGlobalObject(JSGlobalObject* globalObject) { m_globalObject = globalObject; }
141 JSGlobalObject* globalObject() { return m_globalObject; }
142
143 bool grow(Register* newEnd);
144 void shrink(Register* newEnd);
145
146 void setNumGlobals(size_t numGlobals) { m_numGlobals = numGlobals; }
147 int numGlobals() const { return m_numGlobals; }
148 size_t maxGlobals() const { return m_maxGlobals; }
149
150 Register* lastGlobal() const { return m_start - m_numGlobals; }
151
152 void markGlobals(Heap* heap) { heap->markConservatively(lastGlobal(), m_start); }
153 void markCallFrames(Heap* heap) { heap->markConservatively(m_start, m_end); }
154
155 private:
156 size_t m_numGlobals;
157 const size_t m_maxGlobals;
158 Register* m_start;
159 Register* m_end;
160 Register* m_max;
161 Register* m_buffer;
162#if HAVE(VIRTUALALLOC)
163 Register* m_commitEnd;
164#endif
165
166 JSGlobalObject* m_globalObject; // The global object whose vars are currently stored in the register file.
167 };
168
169 inline RegisterFile::RegisterFile(size_t capacity, size_t maxGlobals)
170 : m_numGlobals(0)
171 , m_maxGlobals(maxGlobals)
172 , m_start(0)
173 , m_end(0)
174 , m_max(0)
175 , m_buffer(0)
176 , m_globalObject(0)
177 {
178 size_t bufferLength = (capacity + maxGlobals) * sizeof(Register);
179 #if HAVE(MMAP)
180 m_buffer = static_cast<Register*>(mmap(0, bufferLength, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, TAG_FOR_REGISTERFILE_MEMORY, 0));
181 if (m_buffer == MAP_FAILED) {
182 fprintf(stderr, "Could not allocate register file: %d\n", errno);
183 CRASH();
184 }
185 #elif HAVE(VIRTUALALLOC)
186 m_buffer = static_cast<Register*>(VirtualAlloc(0, roundUpAllocationSize(bufferLength, commitSize), MEM_RESERVE, PAGE_READWRITE));
187 if (!m_buffer) {
188 fprintf(stderr, "Could not allocate register file: %d\n", errno);
189 CRASH();
190 }
191 size_t committedSize = roundUpAllocationSize(maxGlobals * sizeof(Register), commitSize);
192 void* commitCheck = VirtualAlloc(m_buffer, committedSize, MEM_COMMIT, PAGE_READWRITE);
193 if (commitCheck != m_buffer) {
194 fprintf(stderr, "Could not allocate register file: %d\n", errno);
195 CRASH();
196 }
197 m_commitEnd = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_buffer) + committedSize);
198 #else
199 #error "Don't know how to reserve virtual memory on this platform."
200 #endif
201 m_start = m_buffer + maxGlobals;
202 m_end = m_start;
203 m_max = m_start + capacity;
204 }
205
206 inline void RegisterFile::shrink(Register* newEnd)
207 {
208 if (newEnd < m_end)
209 m_end = newEnd;
210 }
211
212 inline bool RegisterFile::grow(Register* newEnd)
213 {
214 if (newEnd < m_end)
215 return true;
216
217 if (newEnd > m_max)
218 return false;
219
220#if !HAVE(MMAP) && HAVE(VIRTUALALLOC)
221 if (newEnd > m_commitEnd) {
222 size_t size = roundUpAllocationSize(reinterpret_cast<char*>(newEnd) - reinterpret_cast<char*>(m_commitEnd), commitSize);
223 if (!VirtualAlloc(m_commitEnd, size, MEM_COMMIT, PAGE_READWRITE)) {
224 fprintf(stderr, "Could not allocate register file: %d\n", errno);
225 CRASH();
226 }
227 m_commitEnd = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_commitEnd) + size);
228 }
229#endif
230
231 m_end = newEnd;
232 return true;
233 }
234
235} // namespace JSC
236
237#undef TAG_FOR_REGISTERFILE_MEMORY
238
239#endif // RegisterFile_h
Note: See TracBrowser for help on using the repository browser.