]>
Commit | Line | Data |
---|---|---|
b37bf2e1 | 1 | /* |
9dae56ea | 2 | * Copyright (C) 2008 Apple Inc. All rights reserved. |
b37bf2e1 A |
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 | * | |
9dae56ea | 13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
b37bf2e1 A |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
9dae56ea | 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
b37bf2e1 A |
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 | ||
9dae56ea | 26 | #include "config.h" |
b37bf2e1 | 27 | |
9dae56ea | 28 | #include "ExecutableAllocator.h" |
b37bf2e1 | 29 | |
6fe7ccc8 A |
30 | #if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND) |
31 | #include "CodeProfiling.h" | |
32 | #include <wtf/HashSet.h> | |
33 | #include <wtf/MetaAllocator.h> | |
34 | #include <wtf/PageReservation.h> | |
35 | #if ENABLE(ASSEMBLER_WX_EXCLUSIVE) | |
36 | #include <wtf/PassOwnPtr.h> | |
37 | #endif | |
38 | #include <wtf/ThreadingPrimitives.h> | |
39 | #include <wtf/VMTags.h> | |
40 | #endif | |
41 | ||
42 | // Uncomment to create an artificial executable memory usage limit. This limit | |
43 | // is imperfect and is primarily useful for testing the VM's ability to handle | |
44 | // out-of-executable-memory situations. | |
45 | // #define EXECUTABLE_MEMORY_LIMIT 1000000 | |
46 | ||
9dae56ea | 47 | #if ENABLE(ASSEMBLER) |
b37bf2e1 | 48 | |
6fe7ccc8 | 49 | using namespace WTF; |
9dae56ea | 50 | |
6fe7ccc8 | 51 | namespace JSC { |
9dae56ea | 52 | |
14957cd0 A |
53 | #if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND) |
54 | ||
6fe7ccc8 A |
55 | class DemandExecutableAllocator : public MetaAllocator { |
56 | public: | |
57 | DemandExecutableAllocator() | |
58 | : MetaAllocator(32) // round up all allocations to 32 bytes | |
59 | { | |
60 | MutexLocker lock(allocatorsMutex()); | |
61 | allocators().add(this); | |
62 | // Don't preallocate any memory here. | |
63 | } | |
64 | ||
65 | virtual ~DemandExecutableAllocator() | |
66 | { | |
67 | { | |
68 | MutexLocker lock(allocatorsMutex()); | |
69 | allocators().remove(this); | |
70 | } | |
71 | for (unsigned i = 0; i < reservations.size(); ++i) | |
72 | reservations.at(i).deallocate(); | |
73 | } | |
74 | ||
75 | static size_t bytesAllocatedByAllAllocators() | |
76 | { | |
77 | size_t total = 0; | |
78 | MutexLocker lock(allocatorsMutex()); | |
79 | for (HashSet<DemandExecutableAllocator*>::const_iterator allocator = allocators().begin(); allocator != allocators().end(); ++allocator) | |
80 | total += (*allocator)->bytesAllocated(); | |
81 | return total; | |
82 | } | |
83 | ||
84 | static size_t bytesCommittedByAllocactors() | |
85 | { | |
86 | size_t total = 0; | |
87 | MutexLocker lock(allocatorsMutex()); | |
88 | for (HashSet<DemandExecutableAllocator*>::const_iterator allocator = allocators().begin(); allocator != allocators().end(); ++allocator) | |
89 | total += (*allocator)->bytesCommitted(); | |
90 | return total; | |
91 | } | |
92 | ||
93 | #if ENABLE(META_ALLOCATOR_PROFILE) | |
94 | static void dumpProfileFromAllAllocators() | |
95 | { | |
96 | MutexLocker lock(allocatorsMutex()); | |
97 | for (HashSet<DemandExecutableAllocator*>::const_iterator allocator = allocators().begin(); allocator != allocators().end(); ++allocator) | |
98 | (*allocator)->dumpProfile(); | |
99 | } | |
100 | #endif | |
101 | ||
102 | protected: | |
103 | virtual void* allocateNewSpace(size_t& numPages) | |
104 | { | |
105 | size_t newNumPages = (((numPages * pageSize() + JIT_ALLOCATOR_LARGE_ALLOC_SIZE - 1) / JIT_ALLOCATOR_LARGE_ALLOC_SIZE * JIT_ALLOCATOR_LARGE_ALLOC_SIZE) + pageSize() - 1) / pageSize(); | |
106 | ||
107 | ASSERT(newNumPages >= numPages); | |
108 | ||
109 | numPages = newNumPages; | |
110 | ||
111 | #ifdef EXECUTABLE_MEMORY_LIMIT | |
112 | if (bytesAllocatedByAllAllocators() >= EXECUTABLE_MEMORY_LIMIT) | |
113 | return 0; | |
114 | #endif | |
115 | ||
116 | PageReservation reservation = PageReservation::reserve(numPages * pageSize(), OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true); | |
117 | if (!reservation) | |
118 | CRASH(); | |
119 | ||
120 | reservations.append(reservation); | |
121 | ||
122 | return reservation.base(); | |
123 | } | |
124 | ||
125 | virtual void notifyNeedPage(void* page) | |
126 | { | |
127 | OSAllocator::commit(page, pageSize(), EXECUTABLE_POOL_WRITABLE, true); | |
128 | } | |
129 | ||
130 | virtual void notifyPageIsFree(void* page) | |
131 | { | |
132 | OSAllocator::decommit(page, pageSize()); | |
133 | } | |
134 | ||
135 | private: | |
136 | Vector<PageReservation, 16> reservations; | |
137 | static HashSet<DemandExecutableAllocator*>& allocators() | |
138 | { | |
139 | DEFINE_STATIC_LOCAL(HashSet<DemandExecutableAllocator*>, sAllocators, ()); | |
140 | return sAllocators; | |
141 | } | |
142 | static Mutex& allocatorsMutex() | |
143 | { | |
144 | DEFINE_STATIC_LOCAL(Mutex, mutex, ()); | |
145 | return mutex; | |
146 | } | |
147 | }; | |
148 | ||
149 | #if ENABLE(ASSEMBLER_WX_EXCLUSIVE) | |
150 | void ExecutableAllocator::initializeAllocator() | |
14957cd0 | 151 | { |
6fe7ccc8 | 152 | } |
14957cd0 | 153 | #else |
6fe7ccc8 A |
154 | static DemandExecutableAllocator* gAllocator; |
155 | ||
156 | namespace { | |
157 | static inline DemandExecutableAllocator* allocator() | |
158 | { | |
159 | return gAllocator; | |
160 | } | |
14957cd0 A |
161 | } |
162 | ||
6fe7ccc8 | 163 | void ExecutableAllocator::initializeAllocator() |
14957cd0 | 164 | { |
6fe7ccc8 A |
165 | ASSERT(!gAllocator); |
166 | gAllocator = new DemandExecutableAllocator(); | |
167 | CodeProfiling::notifyAllocator(gAllocator); | |
168 | } | |
169 | #endif | |
170 | ||
171 | ExecutableAllocator::ExecutableAllocator(JSGlobalData&) | |
172 | #if ENABLE(ASSEMBLER_WX_EXCLUSIVE) | |
173 | : m_allocator(adoptPtr(new DemandExecutableAllocator())) | |
174 | #endif | |
175 | { | |
176 | ASSERT(allocator()); | |
14957cd0 A |
177 | } |
178 | ||
6fe7ccc8 | 179 | ExecutableAllocator::~ExecutableAllocator() |
14957cd0 | 180 | { |
14957cd0 A |
181 | } |
182 | ||
183 | bool ExecutableAllocator::isValid() const | |
184 | { | |
185 | return true; | |
186 | } | |
6fe7ccc8 | 187 | |
14957cd0 A |
188 | bool ExecutableAllocator::underMemoryPressure() |
189 | { | |
6fe7ccc8 A |
190 | #ifdef EXECUTABLE_MEMORY_LIMIT |
191 | return DemandExecutableAllocator::bytesAllocatedByAllAllocators() > EXECUTABLE_MEMORY_LIMIT / 2; | |
192 | #else | |
14957cd0 | 193 | return false; |
6fe7ccc8 | 194 | #endif |
14957cd0 | 195 | } |
6fe7ccc8 A |
196 | |
197 | double ExecutableAllocator::memoryPressureMultiplier(size_t addedMemoryUsage) | |
198 | { | |
199 | double result; | |
200 | #ifdef EXECUTABLE_MEMORY_LIMIT | |
201 | size_t bytesAllocated = DemandExecutableAllocator::bytesAllocatedByAllAllocators() + addedMemoryUsage; | |
202 | if (bytesAllocated >= EXECUTABLE_MEMORY_LIMIT) | |
203 | bytesAllocated = EXECUTABLE_MEMORY_LIMIT; | |
204 | result = static_cast<double>(EXECUTABLE_MEMORY_LIMIT) / | |
205 | (EXECUTABLE_MEMORY_LIMIT - bytesAllocated); | |
206 | #else | |
207 | UNUSED_PARAM(addedMemoryUsage); | |
208 | result = 1.0; | |
209 | #endif | |
210 | if (result < 1.0) | |
211 | result = 1.0; | |
212 | return result; | |
213 | ||
214 | } | |
215 | ||
216 | PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(JSGlobalData&, size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort) | |
217 | { | |
218 | RefPtr<ExecutableMemoryHandle> result = allocator()->allocate(sizeInBytes, ownerUID); | |
219 | if (!result && effort == JITCompilationMustSucceed) | |
220 | CRASH(); | |
221 | return result.release(); | |
222 | } | |
223 | ||
14957cd0 A |
224 | size_t ExecutableAllocator::committedByteCount() |
225 | { | |
6fe7ccc8 A |
226 | return DemandExecutableAllocator::bytesCommittedByAllocactors(); |
227 | } | |
14957cd0 | 228 | |
6fe7ccc8 A |
229 | #if ENABLE(META_ALLOCATOR_PROFILE) |
230 | void ExecutableAllocator::dumpProfile() | |
231 | { | |
232 | DemandExecutableAllocator::dumpProfileFromAllAllocators(); | |
233 | } | |
14957cd0 A |
234 | #endif |
235 | ||
6fe7ccc8 A |
236 | #endif // ENABLE(EXECUTABLE_ALLOCATOR_DEMAND) |
237 | ||
4e4e5a6f | 238 | #if ENABLE(ASSEMBLER_WX_EXCLUSIVE) |
14957cd0 | 239 | |
6fe7ccc8 | 240 | #if OS(WINDOWS) |
14957cd0 A |
241 | #error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform." |
242 | #endif | |
243 | ||
244 | void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting) | |
4e4e5a6f | 245 | { |
6fe7ccc8 | 246 | size_t pageSize = WTF::pageSize(); |
4e4e5a6f A |
247 | |
248 | // Calculate the start of the page containing this region, | |
249 | // and account for this extra memory within size. | |
250 | intptr_t startPtr = reinterpret_cast<intptr_t>(start); | |
251 | intptr_t pageStartPtr = startPtr & ~(pageSize - 1); | |
252 | void* pageStart = reinterpret_cast<void*>(pageStartPtr); | |
253 | size += (startPtr - pageStartPtr); | |
254 | ||
255 | // Round size up | |
256 | size += (pageSize - 1); | |
257 | size &= ~(pageSize - 1); | |
258 | ||
259 | mprotect(pageStart, size, (setting == Writable) ? PROTECTION_FLAGS_RW : PROTECTION_FLAGS_RX); | |
260 | } | |
14957cd0 | 261 | |
4e4e5a6f A |
262 | #endif |
263 | ||
9dae56ea A |
264 | } |
265 | ||
266 | #endif // HAVE(ASSEMBLER) |