]>
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() | |
93a37866 | 58 | : MetaAllocator(jitAllocationGranule) |
6fe7ccc8 A |
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); | |
93a37866 | 117 | RELEASE_ASSERT(reservation); |
6fe7ccc8 A |
118 | |
119 | reservations.append(reservation); | |
120 | ||
121 | return reservation.base(); | |
122 | } | |
123 | ||
124 | virtual void notifyNeedPage(void* page) | |
125 | { | |
126 | OSAllocator::commit(page, pageSize(), EXECUTABLE_POOL_WRITABLE, true); | |
127 | } | |
128 | ||
129 | virtual void notifyPageIsFree(void* page) | |
130 | { | |
131 | OSAllocator::decommit(page, pageSize()); | |
132 | } | |
133 | ||
134 | private: | |
135 | Vector<PageReservation, 16> reservations; | |
136 | static HashSet<DemandExecutableAllocator*>& allocators() | |
137 | { | |
138 | DEFINE_STATIC_LOCAL(HashSet<DemandExecutableAllocator*>, sAllocators, ()); | |
139 | return sAllocators; | |
140 | } | |
141 | static Mutex& allocatorsMutex() | |
142 | { | |
143 | DEFINE_STATIC_LOCAL(Mutex, mutex, ()); | |
144 | return mutex; | |
145 | } | |
146 | }; | |
147 | ||
148 | #if ENABLE(ASSEMBLER_WX_EXCLUSIVE) | |
149 | void ExecutableAllocator::initializeAllocator() | |
14957cd0 | 150 | { |
6fe7ccc8 | 151 | } |
14957cd0 | 152 | #else |
6fe7ccc8 A |
153 | static DemandExecutableAllocator* gAllocator; |
154 | ||
155 | namespace { | |
156 | static inline DemandExecutableAllocator* allocator() | |
157 | { | |
158 | return gAllocator; | |
159 | } | |
14957cd0 A |
160 | } |
161 | ||
6fe7ccc8 | 162 | void ExecutableAllocator::initializeAllocator() |
14957cd0 | 163 | { |
6fe7ccc8 A |
164 | ASSERT(!gAllocator); |
165 | gAllocator = new DemandExecutableAllocator(); | |
166 | CodeProfiling::notifyAllocator(gAllocator); | |
167 | } | |
168 | #endif | |
169 | ||
93a37866 | 170 | ExecutableAllocator::ExecutableAllocator(VM&) |
6fe7ccc8 A |
171 | #if ENABLE(ASSEMBLER_WX_EXCLUSIVE) |
172 | : m_allocator(adoptPtr(new DemandExecutableAllocator())) | |
173 | #endif | |
174 | { | |
175 | ASSERT(allocator()); | |
14957cd0 A |
176 | } |
177 | ||
6fe7ccc8 | 178 | ExecutableAllocator::~ExecutableAllocator() |
14957cd0 | 179 | { |
14957cd0 A |
180 | } |
181 | ||
182 | bool ExecutableAllocator::isValid() const | |
183 | { | |
184 | return true; | |
185 | } | |
6fe7ccc8 | 186 | |
14957cd0 A |
187 | bool ExecutableAllocator::underMemoryPressure() |
188 | { | |
6fe7ccc8 A |
189 | #ifdef EXECUTABLE_MEMORY_LIMIT |
190 | return DemandExecutableAllocator::bytesAllocatedByAllAllocators() > EXECUTABLE_MEMORY_LIMIT / 2; | |
191 | #else | |
14957cd0 | 192 | return false; |
6fe7ccc8 | 193 | #endif |
14957cd0 | 194 | } |
6fe7ccc8 A |
195 | |
196 | double ExecutableAllocator::memoryPressureMultiplier(size_t addedMemoryUsage) | |
197 | { | |
198 | double result; | |
199 | #ifdef EXECUTABLE_MEMORY_LIMIT | |
200 | size_t bytesAllocated = DemandExecutableAllocator::bytesAllocatedByAllAllocators() + addedMemoryUsage; | |
201 | if (bytesAllocated >= EXECUTABLE_MEMORY_LIMIT) | |
202 | bytesAllocated = EXECUTABLE_MEMORY_LIMIT; | |
203 | result = static_cast<double>(EXECUTABLE_MEMORY_LIMIT) / | |
204 | (EXECUTABLE_MEMORY_LIMIT - bytesAllocated); | |
205 | #else | |
206 | UNUSED_PARAM(addedMemoryUsage); | |
207 | result = 1.0; | |
208 | #endif | |
209 | if (result < 1.0) | |
210 | result = 1.0; | |
211 | return result; | |
212 | ||
213 | } | |
214 | ||
93a37866 | 215 | PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(VM&, size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort) |
6fe7ccc8 A |
216 | { |
217 | RefPtr<ExecutableMemoryHandle> result = allocator()->allocate(sizeInBytes, ownerUID); | |
93a37866 | 218 | RELEASE_ASSERT(result || effort != JITCompilationMustSucceed); |
6fe7ccc8 A |
219 | return result.release(); |
220 | } | |
221 | ||
14957cd0 A |
222 | size_t ExecutableAllocator::committedByteCount() |
223 | { | |
6fe7ccc8 A |
224 | return DemandExecutableAllocator::bytesCommittedByAllocactors(); |
225 | } | |
14957cd0 | 226 | |
6fe7ccc8 A |
227 | #if ENABLE(META_ALLOCATOR_PROFILE) |
228 | void ExecutableAllocator::dumpProfile() | |
229 | { | |
230 | DemandExecutableAllocator::dumpProfileFromAllAllocators(); | |
231 | } | |
14957cd0 A |
232 | #endif |
233 | ||
6fe7ccc8 A |
234 | #endif // ENABLE(EXECUTABLE_ALLOCATOR_DEMAND) |
235 | ||
4e4e5a6f | 236 | #if ENABLE(ASSEMBLER_WX_EXCLUSIVE) |
14957cd0 | 237 | |
6fe7ccc8 | 238 | #if OS(WINDOWS) |
14957cd0 A |
239 | #error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform." |
240 | #endif | |
241 | ||
242 | void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting) | |
4e4e5a6f | 243 | { |
6fe7ccc8 | 244 | size_t pageSize = WTF::pageSize(); |
4e4e5a6f A |
245 | |
246 | // Calculate the start of the page containing this region, | |
247 | // and account for this extra memory within size. | |
248 | intptr_t startPtr = reinterpret_cast<intptr_t>(start); | |
249 | intptr_t pageStartPtr = startPtr & ~(pageSize - 1); | |
250 | void* pageStart = reinterpret_cast<void*>(pageStartPtr); | |
251 | size += (startPtr - pageStartPtr); | |
252 | ||
253 | // Round size up | |
254 | size += (pageSize - 1); | |
255 | size &= ~(pageSize - 1); | |
256 | ||
257 | mprotect(pageStart, size, (setting == Writable) ? PROTECTION_FLAGS_RW : PROTECTION_FLAGS_RX); | |
258 | } | |
14957cd0 | 259 | |
4e4e5a6f A |
260 | #endif |
261 | ||
9dae56ea A |
262 | } |
263 | ||
264 | #endif // HAVE(ASSEMBLER) |