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.
26 #ifndef ExecutableAllocator_h
27 #define ExecutableAllocator_h
31 #include <wtf/Assertions.h>
32 #include <wtf/PassRefPtr.h>
33 #include <wtf/RefCounted.h>
34 #include <wtf/Vector.h>
38 #define JIT_ALLOCATOR_PAGE_SIZE (ExecutableAllocator::pageSize)
39 #define JIT_ALLOCATOR_LARGE_ALLOC_SIZE (ExecutableAllocator::pageSize * 4)
43 class ExecutablePool
: public RefCounted
<ExecutablePool
> {
49 typedef Vector
<Allocation
, 2> AllocationList
;
52 static PassRefPtr
<ExecutablePool
> create(size_t n
)
54 return adoptRef(new ExecutablePool(n
));
59 ASSERT(m_freePtr
<= m_end
);
61 // Round 'n' up to a multiple of word size; if all allocations are of
62 // word sized quantities, then all subsequent allocations will be aligned.
63 n
= roundUpAllocationSize(n
, sizeof(void*));
65 if (static_cast<ptrdiff_t>(n
) < (m_end
- m_freePtr
)) {
66 void* result
= m_freePtr
;
71 // Insufficient space to allocate in the existing pool
72 // so we need allocate into a new pool
73 return poolAllocate(n
);
78 AllocationList::const_iterator end
= m_pools
.end();
79 for (AllocationList::const_iterator ptr
= m_pools
.begin(); ptr
!= end
; ++ptr
)
80 ExecutablePool::systemRelease(*ptr
);
83 size_t available() const { return (m_pools
.size() > 1) ? 0 : m_end
- m_freePtr
; }
86 static Allocation
systemAlloc(size_t n
);
87 static void systemRelease(const Allocation
& alloc
);
89 inline size_t roundUpAllocationSize(size_t request
, size_t granularity
)
91 if ((std::numeric_limits
<size_t>::max() - granularity
) <= request
)
92 CRASH(); // Allocation is too large
94 // Round up to next page boundary
95 size_t size
= request
+ (granularity
- 1);
96 size
= size
& ~(granularity
- 1);
97 ASSERT(size
>= request
);
101 ExecutablePool(size_t n
);
103 void* poolAllocate(size_t n
);
107 AllocationList m_pools
;
110 class ExecutableAllocator
{
112 static size_t pageSize
;
113 ExecutableAllocator()
117 m_smallAllocationPool
= ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE
);
120 PassRefPtr
<ExecutablePool
> poolForSize(size_t n
)
122 // Try to fit in the existing small allocator
123 if (n
< m_smallAllocationPool
->available())
124 return m_smallAllocationPool
;
126 // If the request is large, we just provide a unshared allocator
127 if (n
> JIT_ALLOCATOR_LARGE_ALLOC_SIZE
)
128 return ExecutablePool::create(n
);
130 // Create a new allocator
131 RefPtr
<ExecutablePool
> pool
= ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE
);
133 // If the new allocator will result in more free space than in
134 // the current small allocator, then we will use it instead
135 if ((pool
->available() - n
) > m_smallAllocationPool
->available())
136 m_smallAllocationPool
= pool
;
137 return pool
.release();
141 RefPtr
<ExecutablePool
> m_smallAllocationPool
;
142 static void intializePageSize();
145 inline ExecutablePool::ExecutablePool(size_t n
)
147 size_t allocSize
= roundUpAllocationSize(n
, JIT_ALLOCATOR_PAGE_SIZE
);
148 Allocation mem
= systemAlloc(allocSize
);
150 m_freePtr
= mem
.pages
;
152 CRASH(); // Failed to allocate
153 m_end
= m_freePtr
+ allocSize
;
156 inline void* ExecutablePool::poolAllocate(size_t n
)
158 size_t allocSize
= roundUpAllocationSize(n
, JIT_ALLOCATOR_PAGE_SIZE
);
160 Allocation result
= systemAlloc(allocSize
);
162 CRASH(); // Failed to allocate
164 ASSERT(m_end
>= m_freePtr
);
165 if ((allocSize
- n
) > static_cast<size_t>(m_end
- m_freePtr
)) {
166 // Replace allocation pool
167 m_freePtr
= result
.pages
+ n
;
168 m_end
= result
.pages
+ allocSize
;
171 m_pools
.append(result
);
177 #endif // ENABLE(ASSEMBLER)
179 #endif // !defined(ExecutableAllocator)