1/*
2 * Copyright (C) 2008 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#ifndef ExecutableAllocator_h
27#define ExecutableAllocator_h
28
29#include <stddef.h> // for ptrdiff_t
30#include <limits>
31#include <wtf/Assertions.h>
32#include <wtf/PassRefPtr.h>
33#include <wtf/RefCounted.h>
34#include <wtf/UnusedParam.h>
35#include <wtf/Vector.h>
36
37#if OS(IPHONE_OS)
38#include <libkern/OSCacheControl.h>
39#include <sys/mman.h>
40#endif
41
42#if OS(SYMBIAN)
43#include <e32std.h>
44#endif
45
46#if OS(WINCE)
47// From pkfuncs.h (private header file from the Platform Builder)
48#define CACHE_SYNC_ALL 0x07F
49extern "C" __declspec(dllimport) void CacheRangeFlush(LPVOID pAddr, DWORD dwLength, DWORD dwFlags);
50#endif
51
52#define JIT_ALLOCATOR_PAGE_SIZE (ExecutableAllocator::pageSize)
53#define JIT_ALLOCATOR_LARGE_ALLOC_SIZE (ExecutableAllocator::pageSize * 4)
54
55#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
56#define PROTECTION_FLAGS_RW (PROT_READ | PROT_WRITE)
57#define PROTECTION_FLAGS_RX (PROT_READ | PROT_EXEC)
58#define INITIAL_PROTECTION_FLAGS PROTECTION_FLAGS_RX
59#else
60#define INITIAL_PROTECTION_FLAGS (PROT_READ | PROT_WRITE | PROT_EXEC)
61#endif
62
63namespace JSC {
64
65inline size_t roundUpAllocationSize(size_t request, size_t granularity)
66{
67 if ((std::numeric_limits<size_t>::max() - granularity) <= request)
68 CRASH(); // Allocation is too large
69
70 // Round up to next page boundary
71 size_t size = request + (granularity - 1);
72 size = size & ~(granularity - 1);
73 ASSERT(size >= request);
74 return size;
75}
76
77}
78
79#if ENABLE(ASSEMBLER)
80
81namespace JSC {
82
83class ExecutablePool : public RefCounted<ExecutablePool> {
84private:
85 struct Allocation {
86 char* pages;
87 size_t size;
88#if OS(SYMBIAN)
89 RChunk* chunk;
90#endif
91 };
92 typedef Vector<Allocation, 2> AllocationList;
93
94public:
95 static PassRefPtr<ExecutablePool> create(size_t n)
96 {
97 return adoptRef(p: new ExecutablePool(n));
98 }
99
100 void* alloc(size_t n)
101 {
102 ASSERT(m_freePtr <= m_end);
103
104 // Round 'n' up to a multiple of word size; if all allocations are of
105 // word sized quantities, then all subsequent allocations will be aligned.
106 n = roundUpAllocationSize(request: n, granularity: sizeof(void*));
107
108 if (static_cast<ptrdiff_t>(n) < (m_end - m_freePtr)) {
109 void* result = m_freePtr;
110 m_freePtr += n;
111 return result;
112 }
113
114 // Insufficient space to allocate in the existing pool
115 // so we need allocate into a new pool
116 return poolAllocate(n);
117 }
118
119 ~ExecutablePool()
120 {
121 AllocationList::const_iterator end = m_pools.end();
122 for (AllocationList::const_iterator ptr = m_pools.begin(); ptr != end; ++ptr)
123 ExecutablePool::systemRelease(alloc: *ptr);
124 }
125
126 size_t available() const { return (m_pools.size() > 1) ? 0 : m_end - m_freePtr; }
127
128private:
129 static Allocation systemAlloc(size_t n);
130 static void systemRelease(const Allocation& alloc);
131
132 ExecutablePool(size_t n);
133
134 void* poolAllocate(size_t n);
135
136 char* m_freePtr;
137 char* m_end;
138 AllocationList m_pools;
139};
140
141class ExecutableAllocator {
142 enum ProtectionSeting { Writable, Executable };
143
144public:
145 static size_t pageSize;
146 ExecutableAllocator()
147 {
148 if (!pageSize)
149 intializePageSize();
150 m_smallAllocationPool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
151 }
152
153 PassRefPtr<ExecutablePool> poolForSize(size_t n)
154 {
155 // Try to fit in the existing small allocator
156 if (n < m_smallAllocationPool->available())
157 return m_smallAllocationPool;
158
159 // If the request is large, we just provide a unshared allocator
160 if (n > JIT_ALLOCATOR_LARGE_ALLOC_SIZE)
161 return ExecutablePool::create(n);
162
163 // Create a new allocator
164 RefPtr<ExecutablePool> pool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
165
166 // If the new allocator will result in more free space than in
167 // the current small allocator, then we will use it instead
168 if ((pool->available() - n) > m_smallAllocationPool->available())
169 m_smallAllocationPool = pool;
170 return pool.release();
171 }
172
173#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
174 static void makeWritable(void* start, size_t size)
175 {
176 reprotectRegion(start, size, Writable);
177 }
178
179 static void makeExecutable(void* start, size_t size)
180 {
181 reprotectRegion(start, size, Executable);
182 }
183#else
184 static void makeWritable(void*, size_t) {}
185 static void makeExecutable(void*, size_t) {}
186#endif
187
188
189#if CPU(X86) || CPU(X86_64)
190 static void cacheFlush(void*, size_t)
191 {
192 }
193#elif CPU(ARM_THUMB2) && OS(IPHONE_OS)
194 static void cacheFlush(void* code, size_t size)
195 {
196 sys_dcache_flush(code, size);
197 sys_icache_invalidate(code, size);
198 }
199#elif CPU(ARM_THUMB2) && OS(LINUX)
200 static void cacheFlush(void* code, size_t size)
201 {
202 asm volatile (
203 "push {r7}\n"
204 "mov r0, %0\n"
205 "mov r1, %1\n"
206 "movw r7, #0x2\n"
207 "movt r7, #0xf\n"
208 "movs r2, #0x0\n"
209 "svc 0x0\n"
210 "pop {r7}\n"
211 :
212 : "r" (code), "r" (reinterpret_cast<char*>(code) + size)
213 : "r0", "r1", "r2");
214 }
215#elif OS(SYMBIAN)
216 static void cacheFlush(void* code, size_t size)
217 {
218 User::IMB_Range(code, static_cast<char*>(code) + size);
219 }
220#elif CPU(ARM_TRADITIONAL) && OS(LINUX)
221 static void cacheFlush(void* code, size_t size)
222 {
223 asm volatile (
224 "push {r7}\n"
225 "mov r0, %0\n"
226 "mov r1, %1\n"
227 "mov r7, #0xf0000\n"
228 "add r7, r7, #0x2\n"
229 "mov r2, #0x0\n"
230 "svc 0x0\n"
231 "pop {r7}\n"
232 :
233 : "r" (code), "r" (reinterpret_cast<char*>(code) + size)
234 : "r0", "r1", "r2");
235 }
236#elif OS(WINCE)
237 static void cacheFlush(void* code, size_t size)
238 {
239 CacheRangeFlush(code, size, CACHE_SYNC_ALL);
240 }
241#else
242 #error "The cacheFlush support is missing on this platform."
243#endif
244
245private:
246
247#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
248 static void reprotectRegion(void*, size_t, ProtectionSeting);
249#endif
250
251 RefPtr<ExecutablePool> m_smallAllocationPool;
252 static void intializePageSize();
253};
254
255inline ExecutablePool::ExecutablePool(size_t n)
256{
257 size_t allocSize = roundUpAllocationSize(request: n, JIT_ALLOCATOR_PAGE_SIZE);
258 Allocation mem = systemAlloc(n: allocSize);
259 m_pools.append(val: mem);
260 m_freePtr = mem.pages;
261 if (!m_freePtr)
262 CRASH(); // Failed to allocate
263 m_end = m_freePtr + allocSize;
264}
265
266inline void* ExecutablePool::poolAllocate(size_t n)
267{
268 size_t allocSize = roundUpAllocationSize(request: n, JIT_ALLOCATOR_PAGE_SIZE);
269
270 Allocation result = systemAlloc(n: allocSize);
271 if (!result.pages)
272 CRASH(); // Failed to allocate
273
274 ASSERT(m_end >= m_freePtr);
275 if ((allocSize - n) > static_cast<size_t>(m_end - m_freePtr)) {
276 // Replace allocation pool
277 m_freePtr = result.pages + n;
278 m_end = result.pages + allocSize;
279 }
280
281 m_pools.append(val: result);
282 return result.pages;
283}
284
285}
286
287#endif // ENABLE(ASSEMBLER)
288
289#endif // !defined(ExecutableAllocator)
290

source code of qtscript/src/3rdparty/javascriptcore/JavaScriptCore/jit/ExecutableAllocator.h