]>
git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGAllocator.h
2 * Copyright (C) 2013 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 DFGAllocator_h
27 #define DFGAllocator_h
31 #include "DFGCommon.h"
32 #include <wtf/StdLibExtras.h>
34 namespace JSC
{ namespace DFG
{
36 // Custom pool allocator for exactly one type (type T). It has fast (O(1), only a few
37 // instructions) allocator, and a similarly fast free(). Recycling works if either of
38 // the following is true:
39 // - T has a trivial destructor. In that case you don't have to ever call free() on
40 // anything. You can just call freeAll() instead.
41 // - You call free() on all T's that you allocated, and never use freeAll().
49 void* allocate(); // Use placement new to allocate, and avoid using this method.
50 void free(T
*); // Call this method to delete; never use 'delete' directly.
52 void freeAll(); // Only call this if you've either freed everything or if T has a trivial destructor.
53 void reset(); // Like freeAll(), but also returns all memory to the OS.
55 unsigned indexOf(const T
*);
57 static Allocator
* allocatorOf(const T
*);
61 void* freeListAllocate();
65 static size_t size() { return 64 * KB
; }
66 static size_t headerSize() { return std::max(sizeof(Region
), sizeof(T
)); }
67 static unsigned numberOfThingsPerRegion() { return (size() - headerSize()) / sizeof(T
); }
68 T
* data() { return bitwise_cast
<T
*>(bitwise_cast
<char*>(this) + headerSize()); }
69 bool isInThisRegion(const T
* pointer
) { return static_cast<unsigned>(pointer
- data()) < numberOfThingsPerRegion(); }
70 static Region
* regionFor(const T
* pointer
) { return bitwise_cast
<Region
*>(bitwise_cast
<uintptr_t>(pointer
) & ~(size() - 1)); }
73 Allocator
* m_allocator
;
77 void freeRegionsStartingAt(Region
*);
78 void startBumpingIn(Region
*);
81 void** m_freeListHead
;
83 unsigned m_bumpRemaining
;
87 inline Allocator
<T
>::Allocator()
95 inline Allocator
<T
>::~Allocator()
101 ALWAYS_INLINE
void* Allocator
<T
>::allocate()
103 void* result
= bumpAllocate();
104 if (LIKELY(!!result
))
106 return freeListAllocate();
110 void Allocator
<T
>::free(T
* object
)
114 void** cell
= bitwise_cast
<void**>(object
);
115 *cell
= m_freeListHead
;
116 m_freeListHead
= cell
;
120 void Allocator
<T
>::freeAll()
123 ASSERT(!m_bumpRemaining
);
124 ASSERT(!m_freeListHead
);
128 // Since the caller is opting out of calling the destructor for any allocated thing,
129 // we have two choices, plus a continuum between: we can either just delete all regions
130 // (i.e. call reset()), or we can make all regions available for reuse. We do something
131 // that optimizes for (a) speed of freeAll(), (b) the assumption that if the user calls
132 // freeAll() then they will probably be calling allocate() in the near future. Namely,
133 // we free all but one region, and make the remaining region a bump allocation region.
135 freeRegionsStartingAt(m_regionHead
->m_next
);
137 m_regionHead
->m_next
= 0;
139 startBumpingIn(m_regionHead
);
143 void Allocator
<T
>::reset()
145 freeRegionsStartingAt(m_regionHead
);
153 unsigned Allocator
<T
>::indexOf(const T
* object
)
155 unsigned numRegions
= 0;
156 for (Region
* region
= m_regionHead
; region
; region
= region
->m_next
)
158 unsigned regionIndex
= 0;
159 for (Region
* region
= m_regionHead
; region
; region
= region
->m_next
) {
160 if (region
->isInThisRegion(object
))
161 return (numRegions
- 1 - regionIndex
) * Region::numberOfThingsPerRegion() + (object
- region
->data());
169 Allocator
<T
>* Allocator
<T
>::allocatorOf(const T
* object
)
171 return Region::regionFor(object
)->m_allocator
;
175 ALWAYS_INLINE
void* Allocator
<T
>::bumpAllocate()
177 if (unsigned remaining
= m_bumpRemaining
) {
179 m_bumpRemaining
= remaining
;
180 return m_bumpEnd
- (remaining
+ 1);
186 void* Allocator
<T
>::freeListAllocate()
188 void** result
= m_freeListHead
;
189 if (UNLIKELY(!result
))
190 return allocateSlow();
191 m_freeListHead
= bitwise_cast
<void**>(*result
);
196 void* Allocator
<T
>::allocateSlow()
198 ASSERT(!m_freeListHead
);
199 ASSERT(!m_bumpRemaining
);
201 if (logCompilationChanges())
202 dataLog("Allocating another allocator region.\n");
204 void* allocation
= fastAlignedMalloc(Region::size(), Region::size());
205 Region
* region
= static_cast<Region
*>(allocation
);
206 region
->m_allocation
= allocation
;
207 region
->m_allocator
= this;
208 startBumpingIn(region
);
209 region
->m_next
= m_regionHead
;
210 m_regionHead
= region
;
212 void* result
= bumpAllocate();
218 void Allocator
<T
>::freeRegionsStartingAt(typename Allocator
<T
>::Region
* region
)
221 Region
* nextRegion
= region
->m_next
;
222 fastAlignedFree(region
->m_allocation
);
228 void Allocator
<T
>::startBumpingIn(typename Allocator
<T
>::Region
* region
)
230 m_bumpEnd
= region
->data() + Region::numberOfThingsPerRegion();
231 m_bumpRemaining
= Region::numberOfThingsPerRegion();
234 } } // namespace JSC::DFG
236 #endif // ENABLE(DFG_JIT)
238 #endif // DFGAllocator_h