2 * Copyright (C) 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #include "ExecutableAllocator.h"
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>
38 #include <wtf/ThreadingPrimitives.h>
39 #include <wtf/VMTags.h>
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
53 #if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND)
55 class DemandExecutableAllocator
: public MetaAllocator
{
57 DemandExecutableAllocator()
58 : MetaAllocator(32) // round up all allocations to 32 bytes
60 MutexLocker
lock(allocatorsMutex());
61 allocators().add(this);
62 // Don't preallocate any memory here.
65 virtual ~DemandExecutableAllocator()
68 MutexLocker
lock(allocatorsMutex());
69 allocators().remove(this);
71 for (unsigned i
= 0; i
< reservations
.size(); ++i
)
72 reservations
.at(i
).deallocate();
75 static size_t bytesAllocatedByAllAllocators()
78 MutexLocker
lock(allocatorsMutex());
79 for (HashSet
<DemandExecutableAllocator
*>::const_iterator allocator
= allocators().begin(); allocator
!= allocators().end(); ++allocator
)
80 total
+= (*allocator
)->bytesAllocated();
84 static size_t bytesCommittedByAllocactors()
87 MutexLocker
lock(allocatorsMutex());
88 for (HashSet
<DemandExecutableAllocator
*>::const_iterator allocator
= allocators().begin(); allocator
!= allocators().end(); ++allocator
)
89 total
+= (*allocator
)->bytesCommitted();
93 #if ENABLE(META_ALLOCATOR_PROFILE)
94 static void dumpProfileFromAllAllocators()
96 MutexLocker
lock(allocatorsMutex());
97 for (HashSet
<DemandExecutableAllocator
*>::const_iterator allocator
= allocators().begin(); allocator
!= allocators().end(); ++allocator
)
98 (*allocator
)->dumpProfile();
103 virtual void* allocateNewSpace(size_t& numPages
)
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();
107 ASSERT(newNumPages
>= numPages
);
109 numPages
= newNumPages
;
111 #ifdef EXECUTABLE_MEMORY_LIMIT
112 if (bytesAllocatedByAllAllocators() >= EXECUTABLE_MEMORY_LIMIT
)
116 PageReservation reservation
= PageReservation::reserve(numPages
* pageSize(), OSAllocator::JSJITCodePages
, EXECUTABLE_POOL_WRITABLE
, true);
120 reservations
.append(reservation
);
122 return reservation
.base();
125 virtual void notifyNeedPage(void* page
)
127 OSAllocator::commit(page
, pageSize(), EXECUTABLE_POOL_WRITABLE
, true);
130 virtual void notifyPageIsFree(void* page
)
132 OSAllocator::decommit(page
, pageSize());
136 Vector
<PageReservation
, 16> reservations
;
137 static HashSet
<DemandExecutableAllocator
*>& allocators()
139 DEFINE_STATIC_LOCAL(HashSet
<DemandExecutableAllocator
*>, sAllocators
, ());
142 static Mutex
& allocatorsMutex()
144 DEFINE_STATIC_LOCAL(Mutex
, mutex
, ());
149 #if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
150 void ExecutableAllocator::initializeAllocator()
154 static DemandExecutableAllocator
* gAllocator
;
157 static inline DemandExecutableAllocator
* allocator()
163 void ExecutableAllocator::initializeAllocator()
166 gAllocator
= new DemandExecutableAllocator();
167 CodeProfiling::notifyAllocator(gAllocator
);
171 ExecutableAllocator::ExecutableAllocator(JSGlobalData
&)
172 #if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
173 : m_allocator(adoptPtr(new DemandExecutableAllocator()))
179 ExecutableAllocator::~ExecutableAllocator()
183 bool ExecutableAllocator::isValid() const
188 bool ExecutableAllocator::underMemoryPressure()
190 #ifdef EXECUTABLE_MEMORY_LIMIT
191 return DemandExecutableAllocator::bytesAllocatedByAllAllocators() > EXECUTABLE_MEMORY_LIMIT
/ 2;
197 double ExecutableAllocator::memoryPressureMultiplier(size_t addedMemoryUsage
)
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
);
207 UNUSED_PARAM(addedMemoryUsage
);
216 PassRefPtr
<ExecutableMemoryHandle
> ExecutableAllocator::allocate(JSGlobalData
&, size_t sizeInBytes
, void* ownerUID
, JITCompilationEffort effort
)
218 RefPtr
<ExecutableMemoryHandle
> result
= allocator()->allocate(sizeInBytes
, ownerUID
);
219 if (!result
&& effort
== JITCompilationMustSucceed
)
221 return result
.release();
224 size_t ExecutableAllocator::committedByteCount()
226 return DemandExecutableAllocator::bytesCommittedByAllocactors();
229 #if ENABLE(META_ALLOCATOR_PROFILE)
230 void ExecutableAllocator::dumpProfile()
232 DemandExecutableAllocator::dumpProfileFromAllAllocators();
236 #endif // ENABLE(EXECUTABLE_ALLOCATOR_DEMAND)
238 #if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
241 #error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform."
244 void ExecutableAllocator::reprotectRegion(void* start
, size_t size
, ProtectionSetting setting
)
246 size_t pageSize
= WTF::pageSize();
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
);
256 size
+= (pageSize
- 1);
257 size
&= ~(pageSize
- 1);
259 mprotect(pageStart
, size
, (setting
== Writable
) ? PROTECTION_FLAGS_RW
: PROTECTION_FLAGS_RX
);
266 #endif // HAVE(ASSEMBLER)