]> git.saurik.com Git - apple/javascriptcore.git/blob - jit/ExecutableAllocatorFixedVMPool.cpp
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / jit / ExecutableAllocatorFixedVMPool.cpp
1 /*
2 * Copyright (C) 2009 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 * 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 *
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.
24 */
25
26 #include "config.h"
27
28 #include "ExecutableAllocator.h"
29
30 #if ENABLE(EXECUTABLE_ALLOCATOR_FIXED)
31
32 #include "CodeProfiling.h"
33 #include <errno.h>
34 #include <sys/mman.h>
35 #include <unistd.h>
36 #include <wtf/MetaAllocator.h>
37 #include <wtf/PageReservation.h>
38 #include <wtf/VMTags.h>
39
40 #if OS(LINUX)
41 #include <stdio.h>
42 #endif
43
44 #define MMAP_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_JIT)
45
46 using namespace WTF;
47
48 namespace JSC {
49
50 #if CPU(ARM)
51 static const size_t fixedPoolSize = 16 * 1024 * 1024;
52 #elif CPU(X86_64)
53 static const size_t fixedPoolSize = 1024 * 1024 * 1024;
54 #else
55 static const size_t fixedPoolSize = 32 * 1024 * 1024;
56 #endif
57
58 class FixedVMPoolExecutableAllocator : public MetaAllocator {
59 public:
60 FixedVMPoolExecutableAllocator()
61 : MetaAllocator(32) // round up all allocations to 32 bytes
62 {
63 m_reservation = PageReservation::reserveWithGuardPages(fixedPoolSize, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
64 #if !(ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
65 if (!m_reservation)
66 CRASH();
67 #endif
68 if (m_reservation) {
69 ASSERT(m_reservation.size() == fixedPoolSize);
70 addFreshFreeSpace(m_reservation.base(), m_reservation.size());
71 }
72 }
73
74 protected:
75 virtual void* allocateNewSpace(size_t&)
76 {
77 // We're operating in a fixed pool, so new allocation is always prohibited.
78 return 0;
79 }
80
81 virtual void notifyNeedPage(void* page)
82 {
83 #if OS(DARWIN)
84 UNUSED_PARAM(page);
85 #else
86 m_reservation.commit(page, pageSize());
87 #endif
88 }
89
90 virtual void notifyPageIsFree(void* page)
91 {
92 #if OS(DARWIN)
93 for (;;) {
94 int result = madvise(page, pageSize(), MADV_FREE);
95 if (!result)
96 return;
97 ASSERT(result == -1);
98 if (errno != EAGAIN) {
99 ASSERT_NOT_REACHED(); // In debug mode, this should be a hard failure.
100 break; // In release mode, we should just ignore the error - not returning memory to the OS is better than crashing, especially since we _will_ be able to reuse the memory internally anyway.
101 }
102 }
103 #else
104 m_reservation.decommit(page, pageSize());
105 #endif
106 }
107
108 private:
109 PageReservation m_reservation;
110 };
111
112 static FixedVMPoolExecutableAllocator* allocator;
113
114 void ExecutableAllocator::initializeAllocator()
115 {
116 ASSERT(!allocator);
117 allocator = new FixedVMPoolExecutableAllocator();
118 CodeProfiling::notifyAllocator(allocator);
119 }
120
121 ExecutableAllocator::ExecutableAllocator(JSGlobalData&)
122 {
123 ASSERT(allocator);
124 }
125
126 ExecutableAllocator::~ExecutableAllocator()
127 {
128 }
129
130 bool ExecutableAllocator::isValid() const
131 {
132 return !!allocator->bytesReserved();
133 }
134
135 bool ExecutableAllocator::underMemoryPressure()
136 {
137 MetaAllocator::Statistics statistics = allocator->currentStatistics();
138 return statistics.bytesAllocated > statistics.bytesReserved / 2;
139 }
140
141 double ExecutableAllocator::memoryPressureMultiplier(size_t addedMemoryUsage)
142 {
143 MetaAllocator::Statistics statistics = allocator->currentStatistics();
144 ASSERT(statistics.bytesAllocated <= statistics.bytesReserved);
145 size_t bytesAllocated = statistics.bytesAllocated + addedMemoryUsage;
146 if (bytesAllocated >= statistics.bytesReserved)
147 bytesAllocated = statistics.bytesReserved;
148 double result = 1.0;
149 size_t divisor = statistics.bytesReserved - bytesAllocated;
150 if (divisor)
151 result = static_cast<double>(statistics.bytesReserved) / divisor;
152 if (result < 1.0)
153 result = 1.0;
154 return result;
155 }
156
157 PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(JSGlobalData& globalData, size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort)
158 {
159 RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes, ownerUID);
160 if (!result) {
161 if (effort == JITCompilationCanFail)
162 return result;
163 releaseExecutableMemory(globalData);
164 result = allocator->allocate(sizeInBytes, ownerUID);
165 if (!result)
166 CRASH();
167 }
168 return result.release();
169 }
170
171 size_t ExecutableAllocator::committedByteCount()
172 {
173 return allocator->bytesCommitted();
174 }
175
176 #if ENABLE(META_ALLOCATOR_PROFILE)
177 void ExecutableAllocator::dumpProfile()
178 {
179 allocator->dumpProfile();
180 }
181 #endif
182
183 }
184
185
186 #endif // ENABLE(EXECUTABLE_ALLOCATOR_FIXED)
187
188 #if !ENABLE(ASSEMBLER)
189 // FIXME: Needed to satisfy JavaScriptCore.exp requirements when building only the interpreter.
190 namespace JSC {
191 size_t ExecutableAllocator::committedByteCount()
192 {
193 return 0;
194 }
195 } // namespace JSC
196 #endif // !ENABLE(JIT)