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(jitAllocationGranule
)
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);
117 RELEASE_ASSERT(reservation
);
119 reservations
.append(reservation
);
121 return reservation
.base();
124 virtual void notifyNeedPage(void* page
)
126 OSAllocator::commit(page
, pageSize(), EXECUTABLE_POOL_WRITABLE
, true);
129 virtual void notifyPageIsFree(void* page
)
131 OSAllocator::decommit(page
, pageSize());
135 Vector
<PageReservation
, 16> reservations
;
136 static HashSet
<DemandExecutableAllocator
*>& allocators()
138 DEFINE_STATIC_LOCAL(HashSet
<DemandExecutableAllocator
*>, sAllocators
, ());
141 static Mutex
& allocatorsMutex()
143 DEFINE_STATIC_LOCAL(Mutex
, mutex
, ());
148 #if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
149 void ExecutableAllocator::initializeAllocator()
153 static DemandExecutableAllocator
* gAllocator
;
156 static inline DemandExecutableAllocator
* allocator()
162 void ExecutableAllocator::initializeAllocator()
165 gAllocator
= new DemandExecutableAllocator();
166 CodeProfiling::notifyAllocator(gAllocator
);
170 ExecutableAllocator::ExecutableAllocator(VM
&)
171 #if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
172 : m_allocator(adoptPtr(new DemandExecutableAllocator()))
178 ExecutableAllocator::~ExecutableAllocator()
182 bool ExecutableAllocator::isValid() const
187 bool ExecutableAllocator::underMemoryPressure()
189 #ifdef EXECUTABLE_MEMORY_LIMIT
190 return DemandExecutableAllocator::bytesAllocatedByAllAllocators() > EXECUTABLE_MEMORY_LIMIT
/ 2;
196 double ExecutableAllocator::memoryPressureMultiplier(size_t addedMemoryUsage
)
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
);
206 UNUSED_PARAM(addedMemoryUsage
);
215 PassRefPtr
<ExecutableMemoryHandle
> ExecutableAllocator::allocate(VM
&, size_t sizeInBytes
, void* ownerUID
, JITCompilationEffort effort
)
217 RefPtr
<ExecutableMemoryHandle
> result
= allocator()->allocate(sizeInBytes
, ownerUID
);
218 RELEASE_ASSERT(result
|| effort
!= JITCompilationMustSucceed
);
219 return result
.release();
222 size_t ExecutableAllocator::committedByteCount()
224 return DemandExecutableAllocator::bytesCommittedByAllocactors();
227 #if ENABLE(META_ALLOCATOR_PROFILE)
228 void ExecutableAllocator::dumpProfile()
230 DemandExecutableAllocator::dumpProfileFromAllAllocators();
234 #endif // ENABLE(EXECUTABLE_ALLOCATOR_DEMAND)
236 #if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
239 #error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform."
242 void ExecutableAllocator::reprotectRegion(void* start
, size_t size
, ProtectionSetting setting
)
244 size_t pageSize
= WTF::pageSize();
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
);
254 size
+= (pageSize
- 1);
255 size
&= ~(pageSize
- 1);
257 mprotect(pageStart
, size
, (setting
== Writable
) ? PROTECTION_FLAGS_RW
: PROTECTION_FLAGS_RX
);
264 #endif // HAVE(ASSEMBLER)